TestCenter Reference
Master.py
Go to the documentation of this file.
1 #
2 # Copyright 2007, MeVis Medical Solutions AG
3 #
4 # The user may use this file in accordance with the license agreement provided with
5 # the Software or, alternatively, in accordance with the terms contained in a
6 # written agreement between the user and MeVis Medical Solutions AG.
7 #
8 # For further information use the contact form at https://www.mevislab.de/contact
9 #
10 
11 
13 
14 # -- system imports ----------------------------------------------------------------------------{{{-
15 import copy
16 import datetime
17 import os
18 import sys
19 import time
20 import logging
21 import traceback
22 import subprocess
23 import tempfile
24 import threading
25 
26 from copy import deepcopy
27 
28 import xml.etree.cElementTree as etree
29 
30 try:
31  import TestSupport
32 except:
33  pass
34 
35 # ----------------------------------------------------------------------------------------------}}}-
36 
37 # -- local imports -----------------------------------------------------------------------------{{{-
38 from . import Config
39 from . import IPC
40 from . import Utils
41 
42 from .LogHandler import LogHandler
43 
44 if sys.version_info.major >= 3:
45  unicode = str
46 
47 # ----------------------------------------------------------------------------------------------}}}-
48 
49 class TestCaseTimer():
50  def __init__(self, seconds):
51  self.startstart = time.time()
52  self.availableSecondsavailableSeconds = seconds
53 
55  passedSeconds = time.time() - self.startstart
56  return self.availableSecondsavailableSeconds - passedSeconds
57 
58  def isExpired(self):
59  return self.getSecondsRemaininggetSecondsRemaining() <= 0.0
60 
61 
62 # ----------------------------------------------------------------------------------------------}}}-
63 
65  nextSlaveId = 0
66 
67  def __init__(self, config, logfileDir, env, isInsideTestCaseManager):
68  self.__id__id = SlaveProcess.nextSlaveId
69  SlaveProcess.nextSlaveId += 1
70  self.__wasKilled__wasKilled = False
71  self.__hasStarted__hasStarted = False
72  self.__logFileFD__logFileFD = None
73  self.__logFile__logFile = None
74  self.__slaveLogFile__slaveLogFile = None
75  self.__logger__logger = logging.getLogger("TestCenter")
76  self.__workDir__workDir = os.path.join(config.getResultDir(), "work")
77 
78  cmd = self.__getCommandLine__getCommandLine(config, logfileDir, isInsideTestCaseManager)
79  if cmd:
80  self.__startProcess__startProcess(cmd, config, env)
81 
82  def hasStarted(self):
83  return self.__hasStarted__hasStarted
84 
85  def __getCommandLine(self, config, logfileDir, isInsideTestCaseManager):
86  try:
87  cmd = config.getMLABTestCenterCommand(macroName="TestCenter")
88  if cmd:
89  self.__slaveLogFile__slaveLogFile = os.path.join(logfileDir, f"slaveLogfile_{self.getID()}.log")
90  cmd.insert(1, '-logfile')
91  cmd.insert(2, self.__slaveLogFile__slaveLogFile)
92  if isInsideTestCaseManager:
93  cmd.append('--started-from-test-case-manager')
95  cmd = None
96 
97  if not cmd:
98  self.__logger__logger.error("Failed to start slave as no MeVisLab executable was found. " + \
99  "Please verify your configuration (see TestCase Manager's " + \
100  "Configuration tab or check the file %s)!" % config.getConfigFilePath())
101  return cmd
102 
103  def __startProcess(self, cmd, _, env):
104  self.__logFileFD__logFileFD, self.__logFile__logFile = tempfile.mkstemp()
105  self.__logger__logger.debug('Starting slave with command line %s' % ' '.join(cmd))
106  try:
107  preexec_fn = os.setpgrp if Utils.isUnix else None
108  self.__process__process = subprocess.Popen(cmd, cwd=self.__workDir__workDir, preexec_fn=preexec_fn, env=env,
109  stdin=subprocess.PIPE,
110  stdout=self.__logFileFD__logFileFD, stderr=self.__logFileFD__logFileFD)
111  self.__hasStarted__hasStarted = True
112  except OSError:
113  self.__logger__logger.error("Failed to start slave (%s)\n%s" % (cmd, traceback.format_exc()))
114 
115  def getID(self):
116  return self.__id__id
117 
118  def getPID(self):
119  return self.__process__process.pid
120 
121  def isRunning(self):
122  return self.getExitCodegetExitCode() is None
123 
124  def getExitCode(self):
125  return self.__process__process.poll()
126 
127  def kill(self):
128  self.__wasKilled__wasKilled = Utils.kill(self.__process__process)
129  return self.__wasKilled__wasKilled
130 
131  def wasKilled(self):
132  return self.__wasKilled__wasKilled
133 
134  def __printLogsAfterError(self):
135  try:
136  output = ''
137  if self.__slaveLogFile__slaveLogFile is not None and os.path.exists(self.__slaveLogFile__slaveLogFile):
138  with open(self.__slaveLogFile__slaveLogFile, 'r', errors="replace") as fh:
139  output = fh.read()
140  if os.path.exists(self.__logFile__logFile):
141  with open(self.__logFile__logFile, 'r', errors="replace") as fh:
142  output += fh.read()
143  if not output:
144  output = 'none'
145  self.logErrorWithPIDlogErrorWithPID('Slave output: %s' % output)
146  except IOError as e:
147  self.logErrorWithPIDlogErrorWithPID(f"Could not read log file: {e}")
148 
149  def finish(self, printLog):
150  try:
151  os.fsync(self.__logFileFD__logFileFD)
152  os.close(self.__logFileFD__logFileFD)
153  except IOError as e:
154  self.logErrorWithPIDlogErrorWithPID("Could not close log file: %s" % str(e))
155  if printLog:
156  self.__printLogsAfterError__printLogsAfterError()
157  if os.path.exists(self.__logFile__logFile):
158  try:
159  Utils.removeFile(self.__logFile__logFile)
160  except IOError as e:
161  self.logErrorWithPIDlogErrorWithPID("Could not remove log file: %s" % str(e))
162  else:
163  self.logMessageWithPIDlogMessageWithPID("Log file does not exist: %s" % self.__logFile__logFile)
164 
165  def logMessageWithPID(self, message):
166  return "%s (PID: %s)" % (message, str(self.getPIDgetPID()))
167 
168  def logDebugWithPID(self, message):
169  self.__logger__logger.debug(self.logMessageWithPIDlogMessageWithPID(message))
170 
171  def logErrorWithPID(self, message):
172  self.__logger__logger.error(self.logMessageWithPIDlogMessageWithPID(message))
173 
174 
175 class ProgressTestCase(object):
176  def __init__(self, name, status, errorCount, warningCount, duration):
177  self.durationduration = duration
178  self.namename = name
179  self.statusstatus = status
180  self.errorCounterrorCount = errorCount
181  self.warningCountwarningCount = warningCount
182 
183 
184 class TestProgress(object):
185  def __init__(self):
186  self.activeTestCaseactiveTestCase = None
187  self.finishedTestCasesfinishedTestCases = []
188  self.testCaseCounttestCaseCount = 0
189 
190  def reset(self, testCaseCount):
191  self.activeTestCaseactiveTestCase = None
192  self.finishedTestCasesfinishedTestCases = []
193  self.testCaseCounttestCaseCount = testCaseCount
194 
195 
196 # -- Class Master ------------------------------------------------------------------------------{{{-
197 
203 class Master (object):
204  # -- member variables ------------------------------------------------------------------------{{{-
205 
206  __config = None
207 
208  __com = None
209 
210  # Slave instance to use if offline testing is used.
211  __slave = None
212 
213  __slaveProc = None
214 
215 
216  __hangingSlaves = []
217 
218  # The configuration of the current test run.
219  __testCfg = None
220 
221  __xmlRoot = None
222 
223 
224  __logger = None
225 
226 
227  __testCasesToIgnoreList = []
228 
229  # --------------------------------------------------------------------------------------------}}}-
230 
231  # -- def __init__ ----------------------------------------------------------------------------{{{-
232 
240  def __init__ (self, cfgFile=None, verbose=False, slave=None, slaveEnvironment=None,
241  isInsideTestCaseManager=False):
242  self.__logger__logger = logging.getLogger("TestCenter")
243 
244  self.__config__config = Config.Configuration(cfgFile)
245 
246  self.__com__com = None if slave is not None else IPC.ComMaster(connectTimeout=self.__config__config.getIPCConnectionTimeout())
247  self.__slave__slave = slave
248  self.__slaveEnvironment__slaveEnvironment = slaveEnvironment
249 
250  self.__testProgress__testProgress = TestProgress()
251  self.__shouldStop__shouldStop = False
252  self.__lock__lock = threading.Lock()
253 
254  self.__testCaseListener__testCaseListener = None
255 
256  self.__testedPkgList__testedPkgList = []
257 
258  # Clean up existing result directory or create it.
259  resultDir = self.__config__config.getResultDir()
260  imgDir = os.path.join(resultDir, "images")
261  fileDir = os.path.join(resultDir, "files")
262  workDir = os.path.join(resultDir, "work")
263  self.logfileDirlogfileDir = os.path.join(resultDir, "logfiles")
264 
265  if not os.path.exists(resultDir):
266  os.makedirs(resultDir)
267  # Clean up old file directory.
268  Utils.rmtree(fileDir)
269  os.makedirs(fileDir)
270  # Clean up old image directory.
271  Utils.rmtree(imgDir)
272  os.makedirs(imgDir)
273  # Clean up old work directory.
274  Utils.rmtree(workDir)
275  os.makedirs(workDir)
276  # Clean up old logfile directory.
277  Utils.rmtree(self.logfileDirlogfileDir)
278  os.makedirs(self.logfileDirlogfileDir)
279 
280  self.__isInsideTestCaseManager__isInsideTestCaseManager = isInsideTestCaseManager
281 
282  self.__testCfg__testCfg = self.__testConfigSkeleton__testConfigSkeleton()
283 
284  self.__updateProgressFunc__updateProgressFunc = None
285 
286  # If not running offline start a second MeVisLab instance.
287  if self.__slave__slave is None:
288  if not self.__startSlave__startSlave():
289  raise Exception("Failed to start slave")
290 
291  # --------------------------------------------------------------------------------------------}}}-
292 
293  def onExit(self):
294  for slaveProc in self.__hangingSlaves__hangingSlaves:
295  slaveProc.finish(printLog=True)
296  if not slaveProc.kill():
297  self.__logger__logger.error("Finally killing process %s failed." % slaveProc.getPID())
298  self.__hangingSlaves__hangingSlaves.clear()
299 
300  def __enter__(self):
301  return self
302 
303  def __exit__(self, *_):
304  self.onExitonExit()
305 
306  def __del__(self):
307  self.onExitonExit()
308 
309  # --------------------------------------------------------------------------------------------}}}-
310 
311  def stop(self):
312  self.__lock__lock.acquire()
313  self.__shouldStop__shouldStop = True
314  self.__lock__lock.release()
315 
316  def shouldStop(self):
317  self.__lock__lock.acquire()
318  result = self.__shouldStop__shouldStop
319  self.__lock__lock.release()
320  return result
321 
322  def getTestProgress(self):
323  self.__lock__lock.acquire()
324  result = copy.deepcopy(self.__testProgress__testProgress)
325  self.__lock__lock.release()
326  return result
327 
328  def resetTestProgress(self, testCaseCount):
329  self.__lock__lock.acquire()
330  self.__testProgress__testProgress.reset(testCaseCount)
331  self.__lock__lock.release()
332 
333  def updateTestProgress(self, finishedTestCase=None, additionalTestCaseCount=None):
334  progressTestCase = None
335  if finishedTestCase is not None:
336  errorCount = 0
337  warningCount = 0
338  for function in finishedTestCase.findall("Function"):
339  status = int(function.get("status", str(Utils.TEST_STATUS_DISABLED)))
340  if status in (Utils.TEST_STATUS_ERROR, Utils.TEST_STATUS_CRASHED,
341  Utils.TEST_STATUS_FUNCTION_NOT_FOUND, Utils.TEST_STATUS_TIMEOUT):
342  errorCount += 1
343  elif status == Utils.TEST_STATUS_WARNING:
344  warningCount += 1
345  progressTestCase = ProgressTestCase(finishedTestCase.get("name"),
346  int(finishedTestCase.get("status", str(Utils.TEST_STATUS_CANCELLED))),
347  errorCount,
348  warningCount,
349  float(finishedTestCase.get("duration", "0")))
350 
351  self.__lock__lock.acquire()
352  if progressTestCase is not None:
353  self.__testProgress__testProgress.finishedTestCases.append(progressTestCase)
354  if additionalTestCaseCount is not None:
355  self.__testProgress__testProgress.testCaseCount += additionalTestCaseCount
356  self.__lock__lock.release()
357 
358  def setUpdateProgressFunc(self, updateProgressFunc):
359  self.__updateProgressFunc__updateProgressFunc = updateProgressFunc
360 
361  def setActiveTestCase(self, testCase):
362  self.__lock__lock.acquire()
363  self.__testProgress__testProgress.activeTestCase = testCase
364  self.__lock__lock.release()
365 
366  # -- def __testConfigSkeleton() --------------------------------------------------------------{{{-
367 
368  def __testConfigSkeleton(self):
369  return etree.fromstring("""
370  <Configuration>
371  <TestGroups />
372  <TestCases />
373  <TestSuites />
374  <Modules />
375  <Packages>
376  <Tested />
377  <Available />
378  <Ignored />
379  </Packages>
380  <TestOptions />
381  </Configuration>""")
382  # --------------------------------------------------------------------------------------------}}}-
383 
384  def setTestCaseListener(self, listener):
385  self.__testCaseListener__testCaseListener = listener
386 
387  # -- def setTestCases ------------------------------------------------------------------------{{{-
388 
390  def setTestCases (self, testCaseList):
391  assert self.__xmlRoot__xmlRoot == None
392 
393  xmlNode = self.__testCfg__testCfg.find("TestCases")
394  for testCaseName in testCaseList:
395  etree.SubElement(xmlNode, "TestCase", name=testCaseName)
396  # --------------------------------------------------------------------------------------------}}}-
397 
398  # -- def setIgnoreTestCases ------------------------------------------------------------------------{{{-
399 
401  def setTestCasesToIgnore (self, testCaseToIgnoreList):
402  self.__testCasesToIgnoreList__testCasesToIgnoreList__testCasesToIgnoreList = testCaseToIgnoreList
403  # --------------------------------------------------------------------------------------------}}}-
404 
405  # -- def setTestGroups -----------------------------------------------------------------------{{{-
406 
408  def setTestGroups (self, testGroupList):
409  assert self.__xmlRoot__xmlRoot == None
410 
411  xmlNode = self.__testCfg__testCfg.find("TestGroups")
412  for testGroupName in testGroupList:
413  etree.SubElement(xmlNode, "TestGroup", name=testGroupName)
414  # --------------------------------------------------------------------------------------------}}}-
415 
416  def setTestSuites (self, testSuiteList):
417  assert self.__xmlRoot__xmlRoot == None
418 
419  xmlNode = self.__testCfg__testCfg.find("TestSuites")
420  for testSuiteName in testSuiteList:
421  etree.SubElement(xmlNode, "TestSuite", name=testSuiteName)
422 
423 
424  # -- def setModules --------------------------------------------------------------------------{{{-
425 
430  def setModules (self, moduleList=[], filterList=[]):
431  assert self.__xmlRoot__xmlRoot == None
432 
433  xmlNode = self.__testCfg__testCfg.find("Modules")
434  for moduleName in moduleList:
435  etree.SubElement(xmlNode, "Module", name=moduleName)
436  for filter in filterList:
437  etree.SubElement(xmlNode, "Filter").text = filter
438  # --------------------------------------------------------------------------------------------}}}-
439 
440  # -- def setPackages -------------------------------------------------------------------------{{{-
441 
450  def setPackages (self, testedPkgList=[], availablePkgList=[], ignoredPkgList=[]):
451  assert self.__xmlRoot__xmlRoot == None
452 
453  self.__testedPkgList__testedPkgList = testedPkgList
454 
455  xmlNode = self.__testCfg__testCfg.find("Packages/Tested")
456  for packageID in testedPkgList:
457  etree.SubElement(xmlNode, "Package", name=packageID)
458 
459  xmlNode = self.__testCfg__testCfg.find("Packages/Available")
460  for packageID in availablePkgList:
461  etree.SubElement(xmlNode, "Package", name=packageID)
462 
463  xmlNode = self.__testCfg__testCfg.find("Packages/Ignored")
464  for packageID in ignoredPkgList:
465  etree.SubElement(xmlNode, "Package", name=packageID)
466  # --------------------------------------------------------------------------------------------}}}-
467 
468  def __testTypeAndName(self, xmlNode):
469  # Just print anything if we are in verbose mode.
470  testType = xmlNode.get('type')
471  testName = xmlNode.get('name') if testType == 'FunctionalTestCase' else "%s::%s" % (xmlNode.get('name'), xmlNode.get('module'))
472 
473  return testType, testName
474 
475  # -- def __statusMessage ---------------------------------------------------------------------{{{-
476 
480  def __statusMessage (self, xmlNode, status):
481  assert type(status) == int
482  assert xmlNode.tag == 'TestCase'
483 
484  statusStr = Utils.getStatusString(status)
485  testType, testName = self.__testTypeAndName__testTypeAndName(xmlNode)
486  fillIn = "."*(80-len(testType+testName+statusStr)-2)
487  msg = "%s::%s%s%s" % (testType, testName, fillIn, statusStr)
488  if status == Utils.TEST_STATUS_OK or status == Utils.TEST_STATUS_DO_NOT_TEST_MODULE:
489  self.__logger__logger.debug(msg)
490  elif status == Utils.TEST_STATUS_WARNING:
491  self.__logger__logger.warning(msg)
492  else:
493  self.__logger__logger.error(msg)
494 
495  # --------------------------------------------------------------------------------------------}}}-
496 
497  # -- def __testFailed ------------------------------------------------------------------------{{{-
498 
508  def __testFailed (self, xmlNode, comError):
509  assert xmlNode.tag == "TestCase"
510 
511  testType = xmlNode.get('type')
512  if testType == u"GenericTestCase":
513  testName = "%s::%s" % (xmlNode.get('name'), xmlNode.get('module'))
514  else:
515  testName = xmlNode.get('name')
516 
517  # Build a mapping from function names to result nodes.
518  funcDict = {}
519  for funcNode in xmlNode.findall('Function'):
520  funcDict.setdefault(funcNode.get('name'), funcNode)
521 
522  # With the previously gathered error status the reason can be determined.
523  status = Utils.TEST_STATUS_ERROR
524  if comError in (IPC.Error.EMPTY_MESSAGE, IPC.Error.ON_RECEIVING_2):
525  status = Utils.TEST_STATUS_CRASHED
526  elif comError == IPC.Error.ON_RECEIVING_TIMEOUT:
527  status = Utils.TEST_STATUS_TIMEOUT
528 
529  # Read the slave's logfile and parse it to get as much results as possible.
530  logHandler = LogHandler(self.__config__config.getSlaveLogFilePath())
531  logHandler.parseLogFile(testType, testName, status, funcDict)
532 
533  return status
534  # --------------------------------------------------------------------------------------------}}}-
535 
536  # -- def __buildTestAgenda -------------------------------------------------------------------{{{-
537 
540  def __buildTestAgenda (self):
541  resultNode = self.__sendRequest__sendRequest("BuildTestAgenda", self.__testCfg__testCfg)
542  if resultNode.get('errorCode') != "Ok":
543  self.__logger__logger.critical("Error (%s) in generating the test agenda!\n%s" % (resultNode.get('errorCode'), resultNode.find('Error').text))
544  return False
545  self.__xmlRoot__xmlRoot = resultNode.find('TestRun')
546  self.__testCfg__testCfg = self.__verifyConfiguration__verifyConfiguration(resultNode.find('Configuration'))
547 
548  # Set package list as testing is started afterwards.
549  self.__sendRequest__sendRequest('SetPackageList', self.__testCfg__testCfg.find('Packages'), 5, restart=True)
550  return True
551  # --------------------------------------------------------------------------------------------}}}-
552 
553  # -- def __buildTestCaseAgenda -------------------------------------------------------------------{{{-
554  def __buildTestCaseAgenda (self, testCaseNode):
555  parameterNode = etree.Element('Parameters')
556  genericTestCase = True # is it possible to determine the testcase type here?
557  if genericTestCase:
558  moduleList = []
559  for module in self.__xmlRoot__xmlRoot.findall('Information/Modules/Module'):
560  moduleList.append(module.attrib['name'])
561  parameterNode.attrib['modules'] = ','.join(moduleList)
562  if len(self.__testedPkgList__testedPkgList) > 0:
563  parameterNode.attrib['packages'] = ','.join(self.__testedPkgList__testedPkgList)
564  else:
565  # test every package
566  parameterNode.attrib['packages'] = '*/*'
567  parameterNode.append(testCaseNode)
568  resultNode = self.__sendRequest__sendRequest("BuildTestCaseAgenda", parameterNode, restart=True)
569  if resultNode.get('errorCode') != "Ok":
570  self.__logger__logger.critical("Error (%s) in generating the test case agenda!\n%s" % (resultNode.get('errorCode'), resultNode.find('Error').text))
571  return None
572 
573  return resultNode
574 
575  # --------------------------------------------------------------------------------------------}}}-
576 
577  # -- def __verifyConfiguration ---------------------------------------------------------------{{{-
578 
585  def __verifyConfiguration (self, testCfg):
586  # Verify package settings.
587  packageRoot = testCfg.find('Packages')
588 
589  tPkgNode = packageRoot.find('Tested')
590  for packageNode in tPkgNode.findall('Package'):
591  if packageNode.get('status') not in ('Ok', 'Added', 'Substituted'):
592  self.__logger__logger.error("Failed to verify package (%s with status '%s')!" % (packageNode.get('name'), packageNode.get('status')))
593 
594  aPkgNode = packageRoot.find('Available')
595  for packageNode in aPkgNode.findall('Package'):
596  if packageNode.get('status') not in ('Ok', 'Added', 'Substituted'):
597  self.__logger__logger.error("Failed to verify package (%s with status '%s')!" % (packageNode.get('name'), packageNode.get('status')))
598  else:
599  if packageNode.get('status') not in ('Substituted'):
600  packageRoot.append(packageNode)
601 
602  packageRoot.remove(tPkgNode)
603  packageRoot.remove(aPkgNode)
604 
605  iPkgNode = packageRoot.find('Ignored')
606  packageRoot.remove(iPkgNode)
607 
608  # Verify the module settings.
609  for moduleNode in testCfg.findall('Modules/Module'):
610  isModuleFiltered = moduleNode.get('isModuleFiltered') == str(True)
611  if not isModuleFiltered and moduleNode.get('status') != str(Utils.TEST_STATUS_OK):
612  self.__logger__logger.error("Failed to verify module (%s with status '%s')" % (moduleNode.get('name'), moduleNode.get('status')))
613  testCfg.find('Modules').clear()
614 
615  # Verify the test case settings.
616  for testCaseNode in testCfg.findall('TestCases/TestCase'):
617  isNotInTestGroups = testCaseNode.get('isNotInTestGroups') == str(True)
618  if not isNotInTestGroups and testCaseNode.get('status') != str(Utils.TEST_STATUS_OK):
619  self.__logger__logger.error("Failed to verify test case (%s with status '%s')" % (testCaseNode.get('name'), testCaseNode.get('status')))
620  testCfg.find('TestCases').clear()
621 
622  return testCfg
623  # --------------------------------------------------------------------------------------------}}}-
624 
625  def __createTimeoutTooHighErrorFunction(self, testCaseInfoNode, testResultNode, timeout):
626  functionName = 'TEST001_VerifyTestCaseTimeout'
627  testFunctions = testCaseInfoNode.find('TestFunctions')
628  testFunction = etree.SubElement(testFunctions, "Function")
629  testFunction.attrib = {'basename': 'VerifyTestCaseTimeout', 'is_disabled': 'False', 'name': functionName}
630  etree.SubElement(testFunction, "Documentation").text = 'Verifies if the TestCase timeout.'
631  timeoutTooHighTestFunction = etree.SubElement(testResultNode, "Function")
632  timeoutTooHighTestFunction.attrib = {'duration': '0', 'name': functionName, 'status': '2', 'is_disabled': 'False', 'try': '1'}
633  events = etree.SubElement(timeoutTooHighTestFunction, 'Events')
634  filename = testCaseInfoNode.find('File').text
635  line = testCaseInfoNode.find('Line').text
636  event = etree.SubElement(events, 'Event')
637  event.attrib = {'file': filename, 'internal': 'true', 'line': line, 'origin': '', 'type': 'Error',
638  'timestamp': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
639  error = 'The TestCase timeout (%ss) exceeds the maximum allowed timeout (%ss)' % (timeout, self.__config__config.getMaxTestTimeoutSeconds())
640  etree.SubElement(event, 'Message').text = error
641 
642  def __buildListOfTestFunctionsToExecute (self, testCaseInfoNode, testCaseNode, funcList=None):
643  # Build up list of test functions that must be executed.
644  testFuncList = []
645  for funcNode in testCaseInfoNode.findall(".//Function"):
646  funcName = funcNode.get('name')
647  # If user selected to process only specific functions ignore the rest.
648  if funcList and funcName not in funcList and not funcName in Utils.VIRTUAL_TEST_CASE_FUNCTIONS:
649  continue
650 
651  isDisabled = funcNode.get("is_disabled", str(False)) == str(True)
652  if testCaseInfoNode.get('name') in self.__testCasesToIgnoreList__testCasesToIgnoreList__testCasesToIgnoreList:
653  isDisabled = True
654  if isDisabled and funcList:
655  # If a user selected the function, then it should be executed
656  isDisabled = False
657  funcNode.set('is_disabled', str(False))
658  funcResultNode = etree.SubElement(testCaseNode, 'Function', name=funcName, is_disabled=str(isDisabled))
659  testFuncList.append(funcName)
660  return testFuncList
661 
662 
663  # -- def __doTest ----------------------------------------------------------------------------{{{-
664 
670 
671  def __doTest (self, testCaseInfoNode, testResultNode, funcList=None):
672  assert testResultNode.tag == 'TestCase'
673 
674  testCaseNode = deepcopy(testResultNode)
675 
676  # Build up list of test functions that must be executed.
677  testFuncList = self.__buildListOfTestFunctionsToExecute__buildListOfTestFunctionsToExecute(testCaseInfoNode, testCaseNode, funcList)
678 
679  testCaseName = testCaseInfoNode.get('name')
680  if self.__testCaseListener__testCaseListener:
681  self.__testCaseListener__testCaseListener.startTestCase(testCaseName, testFuncList)
682 
683  # Gather time till timeout.
684  hasValidTimeout = True
685  timeout = int(testCaseInfoNode.get('timeout'))
686  if timeout == 0:
687  timeout = self.__config__config.getDefaultTestTimeoutSeconds()
688  if self.__config__config.getMaxTestTimeoutSeconds():
689  if timeout > self.__config__config.getMaxTestTimeoutSeconds():
690  self.__createTimeoutTooHighErrorFunction__createTimeoutTooHighErrorFunction(testCaseInfoNode, testResultNode, timeout)
691  hasValidTimeout = False
692 
693  # Use a bigger timeout if coverage or bullseye are enabled
694  if self.__config__config.isPythonCoverageEnabled():
695  timeout = timeout * 4.
696  if self.__config__config.isBullseyeCoverageEnabled():
697  timeout = timeout * 4.
698 
699  if hasValidTimeout:
700  retries, status = self.__executeTestFunctions__executeTestFunctions(testCaseInfoNode, testResultNode, testCaseNode, testFuncList, timeout)
701  else:
702  retries = 0
703  status = Utils.TEST_STATUS_ERROR
704 
705  # Set status and number of retries for the given test case.
706  testResultNode.set("status", unicode(status))
707  testResultNode.set("retries", unicode(retries))
708  # Print status message.
709  self.__statusMessage__statusMessage(testResultNode, status)
710  if self.__testCaseListener__testCaseListener:
711  self.__testCaseListener__testCaseListener.endTestCase()
712  # --------------------------------------------------------------------------------------------}}}-
713 
714 
715  def transferNodeFromExecutionToResultXML(self, nodeName, executionNode, testResultNode):
716  coverageFile = executionNode.get(nodeName)
717  if executionNode.get(nodeName) is not None:
718  testResultNode.set(nodeName, coverageFile)
719 
720  def __executeTestFunctions (self, testCaseInfoNode, testResultNode, testCaseNode, testFuncList, timeout):
721  if testCaseNode.get('status') == str(Utils.TEST_STATUS_DO_NOT_TEST_MODULE):
722  return 0, Utils.TEST_STATUS_DO_NOT_TEST_MODULE
723 
724  retries = 0
725  failedFuncList = []
726  timer = TestCaseTimer(timeout)
727 
728  status = Utils.TEST_STATUS_OK
729  maxFuncStatus = Utils.TEST_STATUS_OK
730  cancelled = False
731  while testFuncList and not timer.isExpired() and not cancelled:
732  # If not set status to timeout and stop execution of remaining test functions.
733 
734  if self.shouldStopshouldStop():
735  cancelled = True
736  status = Utils.TEST_STATUS_CANCELLED
737  break
738 
739  # if we have a test case listener, we request progress calls from the slave:
740  if self.__testCaseListener__testCaseListener:
741  testCaseNode.set("requestProgress", "1")
742 
743  testCaseNode.set("maxErrorMessagesPerTestFunction", str(self.__config__config.getReportOptions().maxErrorMessagesPerTestFunction))
744  testCaseNode.set("maxInfoMessagesPerTestFunction", str(self.__config__config.getReportOptions().maxInfoMessagesPerTestFunction))
745 
746  # Initiate the processing of the remaining test functions.
747  executionNode = self.__sendRequest__sendRequest("DoTest", testCaseNode, timeout=timer.getSecondsRemaining(), tries=1)
748  if executionNode.get('errorCode') != "Ok":
749  self.__logger__logger.debug('Restarting due to error in test execution.\n%s' % executionNode.find('Error').text)
750 
751  # Try to determine what was the reason for the test to fail.
752  comError = self.__com__com.getLastError() if self.__com__com else 0
753 
754  # Delete slave process.
755  self.stopSlavestopSlave()
756 
757  # Handle logfile to get gathered results.
758  status = self.__testFailed__testFailed(testCaseNode, comError)
759  # Restart slave.
760  if not self.__startSlave__startSlave():
761  self.__logger__logger.debug('Failed to re-start slave.')
762  else:
763  testCaseNode = executionNode.find('TestCase')
764 
765  self.transferNodeFromExecutionToResultXMLtransferNodeFromExecutionToResultXML('pythonCoverage', executionNode, testResultNode)
766  self.transferNodeFromExecutionToResultXMLtransferNodeFromExecutionToResultXML('bullseyeCoverage', executionNode, testResultNode)
767 
768  extraTestCasesResults = testCaseNode.find('ExtraTestCasesResults')
769  if extraTestCasesResults != None:
770  testResultNode.append(deepcopy(extraTestCasesResults))
771 
772  # functions to test.
773  for funcResultNode in testCaseNode.findall('Function'):
774  funcName = funcResultNode.get("name")
775 
776  # If status is not set, the function has not been executed yet.
777  funcStatus = funcResultNode.get("status")
778  if not funcStatus:
779  # Function not processed yet.
780  continue
781  else:
782  funcStatus = int(funcStatus)
783  if maxFuncStatus < funcStatus:
784  maxFuncStatus = funcStatus
785 
786  if funcName not in failedFuncList:
787  funcResultNode.set('try', '1')
788 
789  if funcStatus in (Utils.TEST_STATUS_CRASHED , Utils.TEST_STATUS_TIMEOUT):
790  failedFuncList.append(funcName)
791  retries += 1
792  # Create copy of node as it will be overwritten in the next iteration.
793  testResultNode.append(deepcopy(funcResultNode))
794  funcResultNode.remove(funcResultNode.find("Events"))
795  else:
796  funcResultNode.set('try', '2')
797  failedFuncList.remove(funcName)
798 
799  # Remove all processed but not failed for the first time functions from
800  # the temporary node.
801  if funcName not in failedFuncList:
802  testFuncList.remove(funcName)
803  # Move the processed function to the result node.
804  testResultNode.append(funcResultNode)
805  testCaseNode.remove(funcResultNode)
806  if funcStatus == Utils.TEST_STATUS_CANCELLED or funcStatus == Utils.TEST_STATUS_FUNCTION_NOT_FOUND:
807  cancelled = True
808  break
809 
810  if timer.isExpired():
811  status = Utils.TEST_STATUS_TIMEOUT
812 
813 
814  # The status variable is used for status > 2 to handle situations where:
815  # - all test functions worked but the slave crashed or timed out.
816  # - the test case timed out but had crashes, too (global status should be
817  # timeout).
818  # Otherwise the maximum function status found in the reports is used.
819  status = status if status > Utils.TEST_STATUS_ERROR else maxFuncStatus
820  return retries, status
821 
822 
823  # -- def __handleExtraTestCaseResults --------------------------------------------------------{{{-
824 
827  def __handleExtraTestCaseResults(self, testCaseInfos, resultNode, testResultNode):
828  node = testResultNode.find("ExtraTestCasesResults")
829  if node != None:
830  testResultNode.remove(node)
831  for node in node.findall("ExtraTestCaseResult"):
832  testCaseInfos.append(node.find("Information/TestCase"))
833  extraTestCaseResult = node.find("Result/TestCase")
834  extraTestCaseResult.set("slave_id", testResultNode.get("slave_id"))
835  resultNode.append(extraTestCaseResult)
836  # --------------------------------------------------------------------------------------------}}}-
837 
838  # -- def shouldMeasurePythonCoverageGlobally -------------------------------------------------{{{-
840  return self.__config__config.isPythonCoverageEnabled() and self.__config__config.isGlobalPythonCoverageEnabled()
841  # --------------------------------------------------------------------------------------------}}}-
842 
843  # -- def run ---------------------------------------------------------------------------------{{{-
844 
853  def run(self, funcDict=None, stopSlaveAfterTestRun=True):
854  if not self.__buildTestAgenda__buildTestAgenda():
855  self.__logger__logger.error("Failed to build test agenda.")
856  return None
857 
858  # Start the timer.
859  timeStarted = time.time()
860 
861  testCaseInfos = self.__xmlRoot__xmlRoot.find('Information/TestCases')
862 
863  # Fetch counters which control after what number of testCases MLAB
864  # should be restarted.
865  freshCounterValue = self.__config__config.getRestartInterval()
866  restartCounter = freshCounterValue
867  restartDisabled = (restartCounter == 0)
868 
869  testCaseInfosTestCases = testCaseInfos.findall('TestCase')
870  if self.__testCaseListener__testCaseListener:
871  testNames = []
872  for node in testCaseInfosTestCases:
873  testNames.append(node.get('name'))
874  self.__testCaseListener__testCaseListener.startTestRun(testNames)
875 
876  self.resetTestProgressresetTestProgress(len(testCaseInfosTestCases))
877 
878  failedTestCases = 0
879  finishedTestCases = 0
880  totalTestCases = len(testCaseInfosTestCases)
881 
882  resultNode = self.__xmlRoot__xmlRoot.find('Results')
883  cancelled = False
884  for testCaseNode in testCaseInfosTestCases:
885  if cancelled:
886  testCaseInfos.remove(testCaseNode)
887  self.updateTestProgressupdateTestProgress(finishedTestCase=testCaseNode)
888  continue
889  try:
890  testCaseAgenda = self.__buildTestCaseAgenda__buildTestCaseAgenda(testCaseNode)
891  if testCaseAgenda != None:
892 
893  testCaseInfoNodes = testCaseAgenda.findall('TestCase')
894  assert(len(testCaseInfoNodes) == 1)
895  testCaseInfoNode = testCaseInfoNodes[0]
896 
897  testCaseInfos.remove(testCaseNode)
898  testCaseInfos.append(testCaseInfoNode)
899 
900  testResultNodes = testCaseAgenda.find('Results').findall('TestCase')
901  if len(testResultNodes) > 1:
902  self.updateTestProgressupdateTestProgress(additionalTestCaseCount=len(testResultNodes)-1)
903  totalTestCases += len(testResultNodes)-1
904  for testResultNode in testResultNodes:
905  if cancelled:
906  break
907  try:
908  testCaseName = testCaseInfoNode.get('name')
909  debugType, debugName = self.__testTypeAndName__testTypeAndName(testResultNode)
910 
911  preferredRendererNode = testCaseInfoNode.find('preferredRenderer')
912  preferredRenderer = "" if preferredRendererNode is None else preferredRendererNode.text.lower()
913  forceSoftwareRendering = (preferredRenderer == "software")
914  if preferredRenderer == "hardware" and Utils.isMesaForced():
915  self.__logger__logger.warning('preferredRenderer settings "hardware" detected but use of software driver is enforced.')
916 
917  if not restartDisabled or forceSoftwareRendering:
918  shouldRestart = (restartCounter == 0)
919  if shouldRestart or forceSoftwareRendering:
920  self.__logger__logger.info("Restart slave for test case %s::%s" % (debugType, debugName))
921  if not self.__startSlave__startSlave(forceSoftwareRendering=forceSoftwareRendering):
922  raise Exception('Failed to start slave.')
923 
924  restartCounter = freshCounterValue
925 
926  #decrement counter on each pass
927  restartCounter -= 1
928 
929  self.setActiveTestCasesetActiveTestCase(testCaseName)
930 
931  if self.__updateProgressFunc__updateProgressFunc is not None:
932  self.__updateProgressFunc__updateProgressFunc(testCaseName, failedTestCases, finishedTestCases, totalTestCases)
933 
934  timeFunctionStarted = time.time()
935  funcList = funcDict[testCaseName] if (funcDict and testCaseName in funcDict) else None
936  self.__doTest__doTest(testCaseInfoNode, testResultNode, funcList)
937  timeFunctionStopped = time.time()
938  if int(testResultNode.get("status")) == Utils.TEST_STATUS_CANCELLED:
939  cancelled = True
940 
941  if int(testResultNode.get("status")) in (Utils.TEST_STATUS_CRASHED,
942  Utils.TEST_STATUS_ERROR,
943  Utils.TEST_STATUS_FUNCTION_NOT_FOUND,
944  Utils.TEST_STATUS_TIMEOUT):
945  failedTestCases += 1
946  finishedTestCases += 1
947 
948  testResultNode.set('duration', str(timeFunctionStopped-timeFunctionStarted))
949 
950  testResultNode.set('slave_id', '0' if self.__slave__slave else str(self.__slaveProc__slaveProc.getID()))
951 
952  resultNode.append(testResultNode)
953 
954  self.__handleExtraTestCaseResults__handleExtraTestCaseResults(testCaseInfos, resultNode, testResultNode)
955 
956  except Exception as e:
957  traceback.print_exc()
958  self.__logger__logger.error("Error executing test case %s::%s\n%s" % (debugType, debugName, e))
959  testResultNode.set("status", unicode(Utils.TEST_STATUS_TIMEOUT))
960  self.updateTestProgressupdateTestProgress(finishedTestCase=testResultNode)
961  else:
962  self.__logger__logger.error("Failed to build the test agenda for test case %s." % testCaseNode.get('name', 'unknown'))
963  except Exception as e:
964  self.__logger__logger.error("Error executing test case %s" % e)
965 
966  if self.shouldMeasurePythonCoverageGloballyshouldMeasurePythonCoverageGlobally():
967  resultNode.set("combinePythonCoverage", "True")
968 
969  # Stop the timer.
970  timeStopped = time.time()
971 
972  self.__xmlRoot__xmlRoot.set('timestamp', str(timeStarted))
973  self.__xmlRoot__xmlRoot.set('duration', str(timeStopped-timeStarted))
974 
975  if stopSlaveAfterTestRun:
976  self.stopSlavestopSlave()
977 
978  xml = Utils.saveXMLTree(self.__xmlRoot__xmlRoot, self.__config__config.getResultFile())
979 
980  if self.__testCaseListener__testCaseListener:
981  self.__testCaseListener__testCaseListener.endTestRun()
982 
983  return xml
984  # --------------------------------------------------------------------------------------------}}}-
985 
986  # -- def reset() -----------------------------------------------------------------------------{{{-
987 
990  def reset(self):
991  self.__xmlRoot__xmlRoot = None
992  self.__testCfg__testCfg = self.__testConfigSkeleton__testConfigSkeleton()
993  # --------------------------------------------------------------------------------------------}}}-
994 
995  # -- def getConfig() -------------------------------------------------------------------------{{{-
996  def getConfig (self):
997  return self.__config__config
998  # --------------------------------------------------------------------------------------------}}}-
999 
1000  # -- def __isSlaveRunning -------------------------------------------------------------------------{{{-
1001 
1002  def __isSlaveRunning (self):
1003  return self.__slaveProc__slaveProc and self.__slaveProc__slaveProc.isRunning()
1004 
1005  def __isSlaveStopped(self):
1006  return not self.__isSlaveRunning__isSlaveRunning()
1007  # --------------------------------------------------------------------------------------------}}}-
1008 
1009  def logMessageWithPID(self, message):
1010  pidString = str(self.__slaveProc__slaveProc.getPID()) if self.__slaveProc__slaveProc is not None else str(None)
1011 
1012  return "%s (PID: %s)" % (message, pidString)
1013 
1014  def logDebugWithPID(self, message):
1015  self.__logger__logger.debug(self.logMessageWithPIDlogMessageWithPID(message))
1016 
1017  def logErrorWithPID(self, message):
1018  self.__logger__logger.error(self.logMessageWithPIDlogMessageWithPID(message))
1019 
1020  def logMessageWithLastError(self, message):
1021  errorCode, errorMessage = self.__com__com.getLastErrorWithMessage()
1022  return "%s ([%d] %s)" % (message, errorCode, errorMessage)
1023 
1024  # -- def __startSlave ------------------------------------------------------------------------{{{-
1025 
1029  def __startSlave (self, forceSoftwareRendering=False):
1030  if self.__slave__slave:
1031  return True
1032 
1033  if self.__isSlaveRunning__isSlaveRunning():
1034  if not self.stopSlavestopSlave():
1035  self.__logger__logger.error("Failed to stop the slave before restart.")
1036 
1037  env = Utils.setForceMesa(self.__slaveEnvironment__slaveEnvironment) if forceSoftwareRendering else self.__slaveEnvironment__slaveEnvironment
1038  if self.__com__com:
1039  # server port is given through environment variable
1040  env = Utils.setTestCenterPort(env, self.__com__com.getPort())
1041  slaveProc = SlaveProcess(self.__config__config, self.logfileDirlogfileDir, env, self.__isInsideTestCaseManager__isInsideTestCaseManager)
1042  if slaveProc.hasStarted():
1043  self.__slaveProc__slaveProc = slaveProc
1044  else:
1045  return False
1046 
1047  return self.__connectToSlave__connectToSlave()
1048  # --------------------------------------------------------------------------------------------}}}-
1049 
1050  def __connectToSlave(self):
1051  retries = 0
1052  timerSleep = 1
1053  maxTries = 15
1054  while retries < maxTries and not self.__com__com.connect(timeout = self.__config__config.getIPCConnectionTimeout()):
1055  retries += 1
1056  self.logDebugWithPIDlogDebugWithPID(self.logMessageWithLastErrorlogMessageWithLastError("Failed to connect to slave in %i. try" % retries))
1057 
1058  if not self.__slaveProc__slaveProc.isRunning():
1059  self.__logger__logger.error("Slave died with exit code %s" % self.__slaveProc__slaveProc.getExitCode())
1060  self.__slaveProc__slaveProc.finish(printLog=True)
1061  return False
1062 
1063  # Use a sleep timer to give the slave process more time to start up.
1064  self.__logger__logger.debug("Sleeping for %s seconds" % (timerSleep))
1065  time.sleep(timerSleep)
1066 
1067  if not self.__com__com.isConnected():
1068  # quit the mlab that we were not able to talk to
1069  self.logErrorWithPIDlogErrorWithPID("Failed to connect to slave within %d seconds." % (maxTries*timerSleep))
1070  if not self.stopSlavestopSlave():
1071  self.__logger__logger.error("Failed to stop the slave after connection error.")
1072  self.__slaveProc__slaveProc.finish(printLog=True)
1073  return False
1074  else:
1075  self.logDebugWithPIDlogDebugWithPID("Connected to slave in %s. try" % (retries+1))
1076 
1077  # Send slave a list of packages that are available. On first run an empty
1078  # string is sent; in the __buildTestAgenda call this list will be
1079  # retrieved. Later the verified list of tests will be sent.
1080  if self.__xmlRoot__xmlRoot:
1081  resultNode = self.__sendRequest__sendRequest('SetPackageList', self.__testCfg__testCfg.find('Packages'), 5)
1082  return resultNode.get('errorCode') == "Ok"
1083 
1084  return True
1085 
1086  # -- def stopSlave ---------------------------------------------------------------------------{{{-
1087  # # Stop the slave process.
1088  # If the slave is running this method tries to stop the slave. This method
1089  # will run until the slave has stopped. After 3 tries on unix a KILL signal
1090  # is sent.
1091  # @return True if the slave was stopped.
1092  def stopSlave (self):
1093  if self.__slave__slave:
1094  #ugly special condition for when a running MeVisLab instance is used
1095  #as slave.
1096  return True
1097 
1098  self.logDebugWithPIDlogDebugWithPID("Shutting down slave")
1099 
1100  if not self.__isSlaveStopped__isSlaveStopped():
1101  #try soft shutdown first by requesting clean quit
1102  xmlNode = self.__sendRequest__sendRequest('Quit', timeout=1, tries=1)
1103 
1104  if xmlNode.get('errorCode') == 'Ok':
1105  self.logDebugWithPIDlogDebugWithPID("Response received, waiting for shutdown")
1106  # wait up to five seconds for the slave to stop:
1107  i = 0
1108  while not self.__isSlaveStopped__isSlaveStopped() and i < 10:
1109  time.sleep(0.5)
1110  i += 1
1111 
1112  #kindly asking for shutdown was obviously not enough, enforce shutdown
1113  if not self.__isSlaveStopped__isSlaveStopped():
1114  self.logDebugWithPIDlogDebugWithPID("No response, killing slave")
1115  self.__slaveProc__slaveProc.kill()
1116 
1117  if self.__isSlaveStopped__isSlaveStopped():
1118  self.__slaveProc__slaveProc.finish(printLog=self.__slaveProc__slaveProc.wasKilled())
1119  else:
1120  self.logErrorWithPIDlogErrorWithPID("Failed to kill slave!")
1121  self.__hangingSlaves__hangingSlaves.append(self.__slaveProc__slaveProc)
1122  self.__slaveProc__slaveProc = None
1123 
1124  return self.__isSlaveStopped__isSlaveStopped()
1125  # --------------------------------------------------------------------------------------------}}}-
1126 
1127  # -- def __sendRequest -----------------------------------------------------------------------{{{-
1128 
1135  def __sendRequest (self, command, parameterNode=None, timeout=None, tries=2, restart=False):
1136  trial = 0
1137 
1138  requestNode = etree.Element('Command', type=command)
1139  requestNode.append(parameterNode if parameterNode != None else etree.Element('Dummy'))
1140 
1141  if self.__slave__slave:
1142  self.logDebugWithPIDlogDebugWithPID("Handling '%s' request" % command)
1143  resultNode = self.__slave__slave.runCommand(requestNode)
1144  else:
1145  self.logDebugWithPIDlogDebugWithPID("Sending '%s' request to slave" % command)
1146  resultNode = None
1147  # The default timeout is taken from the configuration file.
1148  if not timeout:
1149  timeout = self.__config__config.getDefaultTestTimeoutSeconds()
1150 
1151  string = None
1152  while ( not string
1153  and (trial < tries)):
1154  timer = TestCaseTimer(timeout)
1155  if self.__com__com.send(etree.tostring(requestNode), timer.getSecondsRemaining()):
1156  # since we allow receiving intermediate "Progress" result values,
1157  # we loop until we receive something that is not a "Progress" message:
1158  while not string and not timer.isExpired():
1159  string = self.__com__com.recv(timer.getSecondsRemaining())
1160  if string:
1161  recvNode = Utils.filterXMLString(string)
1162  self.logDebugWithPIDlogDebugWithPID("Received node of type '%s'" % recvNode.tag)
1163  if recvNode.tag == "Progress":
1164  shouldStop = False
1165  if self.__testCaseListener__testCaseListener:
1166  try:
1167  self.__testCaseListener__testCaseListener.startTestCaseFunction(recvNode.get("testType"), recvNode.get("testCase"), recvNode.get("testFunction"))
1169  shouldStop = True
1170  # tell slave if it should stop or go on:
1171  self.__com__com.send("0" if shouldStop else "1", 5)
1172  string = None
1173  elif recvNode.tag == "Status":
1174  if self.__testCaseListener__testCaseListener:
1175  self.__testCaseListener__testCaseListener.endTestCaseFunction(int(recvNode.get("status")), 0)
1176  string = None
1177  else:
1178  resultNode = recvNode
1179  else:
1180  break
1181 
1182  if not string:
1183  trial += 1
1184 
1185  if restart and (trial < tries):
1186  self.__logger__logger.info("Restarting due to communication error ...")
1187  self.__startSlave__startSlave()
1188 
1189  if resultNode == None:
1190  self.logDebugWithPIDlogDebugWithPID("Error: Received no result from slave.")
1191  resultNode = etree.Element('Result', errorCode='CommunicationError')
1192  etree.SubElement(resultNode, 'Error').text = "Communication error [%d]: %s" % self.__com__com.getLastErrorWithMessage()
1193  self.logDebugWithPIDlogDebugWithPID("Result error code: %s" % resultNode.get('errorCode'))
1194  content = etree.tostring(resultNode).decode()
1195  self.logDebugWithPIDlogDebugWithPID("Result content: %s%s" % (content[:150], " [...]" if len(content)>150 else ""))
1196  return resultNode
1197  # --------------------------------------------------------------------------------------------}}}-
1198 # ----------------------------------------------------------------------------------------------}}}-
The connection's master.
Definition: IPC.py:230
The coordinator of test execution.
Definition: Master.py:203
def logMessageWithPID(self, message)
Definition: Master.py:1009
def setTestCasesToIgnore(self, testCaseToIgnoreList)
Set the list of test cases to ignore.
Definition: Master.py:401
def run(self, funcDict=None, stopSlaveAfterTestRun=True)
The main method which handles all the request from the master.
Definition: Master.py:853
def logMessageWithLastError(self, message)
Definition: Master.py:1020
def setModules(self, moduleList=[], filterList=[])
Specify the list of modules to test.
Definition: Master.py:430
def setUpdateProgressFunc(self, updateProgressFunc)
Definition: Master.py:358
def __testFailed(self, xmlNode, comError)
Definition: Master.py:508
def setActiveTestCase(self, testCase)
Definition: Master.py:361
def __buildListOfTestFunctionsToExecute(self, testCaseInfoNode, testCaseNode, funcList=None)
Definition: Master.py:642
def __createTimeoutTooHighErrorFunction(self, testCaseInfoNode, testResultNode, timeout)
Definition: Master.py:625
def __doTest(self, testCaseInfoNode, testResultNode, funcList=None)
Definition: Master.py:671
def __executeTestFunctions(self, testCaseInfoNode, testResultNode, testCaseNode, testFuncList, timeout)
Definition: Master.py:720
def __statusMessage(self, xmlNode, status)
Definition: Master.py:480
def logDebugWithPID(self, message)
Definition: Master.py:1014
def setTestSuites(self, testSuiteList)
Definition: Master.py:416
def __testTypeAndName(self, xmlNode)
Definition: Master.py:468
def setTestCaseListener(self, listener)
Definition: Master.py:384
def setTestGroups(self, testGroupList)
Set the list of test groups to respect.
Definition: Master.py:408
def setPackages(self, testedPkgList=[], availablePkgList=[], ignoredPkgList=[])
Specify the packages that should be tested and thought available.
Definition: Master.py:450
def __verifyConfiguration(self, testCfg)
Definition: Master.py:585
def shouldMeasurePythonCoverageGlobally(self)
Definition: Master.py:839
def __sendRequest(self, command, parameterNode=None, timeout=None, tries=2, restart=False)
Definition: Master.py:1135
def __init__(self, cfgFile=None, verbose=False, slave=None, slaveEnvironment=None, isInsideTestCaseManager=False)
The default constructor.
Definition: Master.py:241
def transferNodeFromExecutionToResultXML(self, nodeName, executionNode, testResultNode)
Definition: Master.py:715
def reset(self)
Resets the master to the state after instantiation.
Definition: Master.py:990
def updateTestProgress(self, finishedTestCase=None, additionalTestCaseCount=None)
Definition: Master.py:333
def logErrorWithPID(self, message)
Definition: Master.py:1017
def resetTestProgress(self, testCaseCount)
Definition: Master.py:328
def setTestCases(self, testCaseList)
Set the list of test cases to execute.
Definition: Master.py:390
def __startSlave(self, forceSoftwareRendering=False)
Definition: Master.py:1029
def __handleExtraTestCaseResults(self, testCaseInfos, resultNode, testResultNode)
Definition: Master.py:827
def __buildTestCaseAgenda(self, testCaseNode)
Definition: Master.py:554
def __init__(self, name, status, errorCount, warningCount, duration)
Definition: Master.py:176
def logMessageWithPID(self, message)
Definition: Master.py:165
def __getCommandLine(self, config, logfileDir, isInsideTestCaseManager)
Definition: Master.py:85
def __startProcess(self, cmd, _, env)
Definition: Master.py:103
def logErrorWithPID(self, message)
Definition: Master.py:171
def __init__(self, config, logfileDir, env, isInsideTestCaseManager)
Definition: Master.py:67
def logDebugWithPID(self, message)
Definition: Master.py:168
def reset(self, testCaseCount)
Definition: Master.py:190
def error(message, stack=False, type='', depth=0)
Put an error to the log.
Definition: Logging.py:121
def warning(message, stack=False, type='', depth=0)
Put a warning to the log.
Definition: Logging.py:99
def info(message, stack=False, type='', depth=0)
Put an info message to the log.
Definition: Logging.py:78