VirtualBox

Changeset 61293 in vbox


Ignore:
Timestamp:
May 30, 2016 1:07:52 PM (8 years ago)
Author:
vboxsync
Message:

virtual_test_sheriff.py: oops. forgot to commit this.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testmanager/batch/virtual_test_sheriff.py

    r61283 r61293  
    4747
    4848# Test Manager imports
    49 from testmanager.core.db            import TMDatabaseConnection;
    50 from testmanager.core.testbox       import TestBoxLogic, TestBoxData;
    51 from testmanager.core.testset       import TestSetLogic, TestSetData;
    52 from testmanager.core.testresults   import TestResultLogic;
    53 from testmanager.core.useraccount   import UserAccountLogic;
     49from testmanager.core.db                    import TMDatabaseConnection;
     50from testmanager.core.build                 import BuildDataEx;
     51from testmanager.core.failurereason         import FailureReasonLogic;
     52from testmanager.core.testbox               import TestBoxLogic, TestBoxData;
     53from testmanager.core.testcase              import TestCaseDataEx;
     54from testmanager.core.testgroup             import TestGroupData;
     55from testmanager.core.testset               import TestSetLogic, TestSetData;
     56from testmanager.core.testresults           import TestResultLogic;
     57from testmanager.core.testresultfailures    import TestResultFailureLogic, TestResultFailureData;
     58from testmanager.core.useraccount           import UserAccountLogic;
     59
     60
     61class VirtualTestSheriffCaseFile(object):
     62    """
     63    A failure investigation case file.
     64
     65    """
     66
     67
     68    ## Max log file we'll read into memory. (256 MB)
     69    kcbMaxLogRead = 0x10000000;
     70
     71
     72    def __init__(self, oSheriff, oTestSet, oTree, oBuild, oTestBox, oTestGroup, oTestCase):
     73        self.oSheriff       = oSheriff;
     74        self.oTestSet       = oTestSet;     # TestSetData
     75        self.oTree          = oTree;        # TestResultDataEx
     76        self.oBuild         = oBuild;       # BuildDataEx
     77        self.oTestBox       = oTestBox;     # TestBoxData
     78        self.oTestGroup     = oTestGroup;   # TestGroupData
     79        self.oTestCase      = oTestCase;    # TestCaseDataEx
     80        self.sMainLog       = '';           # The main log file.  Empty string if not accessible.
     81
     82        # Generate a case file name.
     83        self.sName          = '#%u: %s' % (self.oTestSet.idTestSet, self.oTestCase.sName,)
     84        self.sLongName      = '#%u: "%s" on "%s" running %s %s (%s), "%s" by %s, using %s %s %s r%u'  \
     85                            % ( self.oTestSet.idTestSet,
     86                                self.oTestCase.sName,
     87                                self.oTestBox.sName,
     88                                self.oTestBox.sOs,
     89                                self.oTestBox.sOsVersion,
     90                                self.oTestBox.sCpuArch,
     91                                self.oTestBox.sCpuName,
     92                                self.oTestBox.sCpuVendor,
     93                                self.oBuild.oCat.sProduct,
     94                                self.oBuild.oCat.sBranch,
     95                                self.oBuild.oCat.sType,
     96                                self.oBuild.iRevision, );
     97
     98        # Investigation notes.
     99        self.tReason            = None;     # None or one of the ktReason_XXX constants.
     100        self.dReasonForResultId = {};       # Reason assignments indexed by idTestResult.
     101
     102    #
     103    # Reason.
     104    #
     105
     106    def noteReason(self, tReason):
     107        """ Notes down a possible reason. """
     108        self.oSheriff.dprint('noteReason: %s -> %s' % (self.tReason, tReason,));
     109        self.tReason = tReason;
     110
     111    def noteReasonForId(self, tReason, idTestResult):
     112        """ Notes down a possible reason for a specific test result. """
     113        self.oSheriff.dprint('noteReasonForId: %u: %s -> %s'
     114                             % (idTestResult, self.dReasonForResultId.get(idTestResult, None), tReason,));
     115        self.dReasonForResultId[idTestResult] = tReason;
     116
     117
     118    #
     119    # Test classification.
     120    #
     121
     122    def isVBoxTest(self):
     123        """ Test classification: VirtualBox (using the build) """
     124        return self.oBuild.oCat.sProduct.lower() in [ 'virtualbox', 'vbox' ];
     125
     126    def isVBoxUnitTest(self):
     127        """ Test case classification: The unit test doing all our testcase/*.cpp stuff. """
     128        return self.isVBoxTest() \
     129           and self.oTestCase.sName.lower() == 'unit tests';
     130
     131    def isVBoxInstallTest(self):
     132        """ Test case classification: VirtualBox Guest installation test. """
     133        return self.isVBoxTest() \
     134           and self.oTestCase.sName.lower().startswith('install:');
     135
     136    def isVBoxSmokeTest(self):
     137        """ Test case classification: Smoke test. """
     138        return self.isVBoxTest() \
     139           and self.oTestCase.sName.lower().startswith('smoketest');
     140
     141
     142    #
     143    # Utility methods.
     144    #
     145
     146    def getMainLog(self):
     147        """
     148        Tries to reads the main log file since this will be the first source of information.
     149        """
     150        if len(self.sMainLog) > 0:
     151            return self.sMainLog;
     152        (oFile, oSizeOrError, _) = self.oTestSet.openFile('main.log', 'rb');
     153        if oFile is not None:
     154            try:
     155                self.sMainLog = oFile.read(min(self.kcbMaxLogRead, oSizeOrError)).decode('utf-8', 'replace');
     156            except Exception as oXcpt:
     157                self.oSheriff.vprint('Error reading main log file: %s' % (oXcpt,))
     158                self.sMainLog = '';
     159        else:
     160            self.oSheriff.vprint('Error opening main log file: %s' % (oSizeOrError,));
     161        return self.sMainLog;
     162
     163    def isSingleTestFailure(self):
     164        """
     165        Figure out if this is a single test failing or if it's one of the
     166        more complicated ones.
     167        """
     168        if self.oTree.cErrors == 1:
     169            return True;
     170        if self.oTree.deepCountErrorContributers() <= 1:
     171            return True;
     172        return False;
     173
    54174
    55175
     
    62182    ksLoginName = 'vsheriff';
    63183
    64 
    65184    def __init__(self):
    66185        """
    67186        Parse command line.
    68187        """
    69         self.oDb = None;
    70         self.tsNow = None;
    71         self.oResultLogic = None;
    72         self.oTestSetLogic = None;
    73         self.oLogin = None;
    74         self.uidSelf = -1;
    75         self.oLogFile = None;
     188        self.oDb                     = None;
     189        self.tsNow                   = None;
     190        self.oTestResultLogic        = None;
     191        self.oTestSetLogic           = None;
     192        self.oFailureReasonLogic     = None;    # FailureReasonLogic;
     193        self.oTestResultFailureLogic = None;    # TestResultFailureLogic
     194        self.oLogin                  = None;
     195        self.uidSelf                 = -1;
     196        self.oLogFile                = None;
    76197
    77198        oParser = OptionParser();
     
    84205        oParser.add_option('-q', '--quiet', dest = 'fQuiet', action = 'store_true', default = False,
    85206                           help = 'Quiet execution');
    86         oParser.add_option('-l', '--log', dest = 'sBuildLogPath', metavar = '<url>', default = None,
    87                            help = 'URL to the build logs (optional).');
     207        oParser.add_option('-l', '--log', dest = 'sLogFile', metavar = '<logfile>', default = None,
     208                           help = 'Where to log messages.');
    88209        oParser.add_option('--debug', dest = 'fDebug', action = 'store_true', default = False,
    89210                           help = 'Enables debug mode.');
     
    91212        (self.oConfig, _) = oParser.parse_args();
    92213
    93         if self.oConfig.sBuildLogPath is not None and len(self.oConfig.sBuildLogPath) > 0:
    94             self.oLogFile = open(self.oConfig.sBuildLogPath, "a");
     214        if self.oConfig.sLogFile is not None and len(self.oConfig.sLogFile) > 0:
     215            self.oLogFile = open(self.oConfig.sLogFile, "a");
    95216            self.oLogFile.write('VirtualTestSheriff: $Revision$ \n');
    96217
     
    126247            self.oLogFile.write('info: %s\n' % (sText,));
    127248        return 0;
     249
     250
     251    def selfCheck(self):
     252        """ Does some self checks, looking up things we expect to be in the database and such. """
     253        rcExit = 0;
     254        for sAttr in dir(self.__class__):
     255            if sAttr.startswith('ktReason_'):
     256                tReason = getattr(self.__class__, sAttr);
     257                oFailureReason = self.oFailureReasonLogic.cachedLookupByNameAndCategory(tReason[1], tReason[0]);
     258                if oFailureReason is None:
     259                    rcExit = self.eprint('Failured to find failure reason "%s" in category "%s" in the database!'
     260                                         % (tReason[1], tReason[0],));
     261
     262        # Check the user account as well.
     263        if self.oLogin is None:
     264            oLogin = UserAccountLogic(self.oDb).tryFetchAccountByLoginName(VirtualTestSheriff.ksLoginName);
     265            if oLogin is None:
     266                rcExit = self.eprint('Cannot find my user account "%s"!' % (VirtualTestSheriff.ksLoginName,));
     267        return rcExit;
     268
    128269
    129270
     
    165306
    166307            # Get the most recent testsets for this box (descending on tsDone) and see how bad it is.
    167             aoSets  = self.oTestSetLogic.fetchResultForTestBox(idTestBox, cHoursBack = cHoursBack, tsNow = tsNow);
     308            aoSets  = self.oTestSetLogic.fetchSetsForTestBox(idTestBox, cHoursBack = cHoursBack, tsNow = tsNow);
    168309            cOkay      = 0;
    169310            cBad       = 0;
     
    209350
    210351
     352    ## @name Failure reasons we know.
     353    ## @{
     354    ktReason_Guru_Generic                              = ( 'Guru Meditations', 'Generic Guru Meditation' );
     355    ktReason_Guru_VERR_IEM_INSTR_NOT_IMPLEMENTED       = ( 'Guru Meditations', 'VERR_IEM_INSTR_NOT_IMPLEMENTED' );
     356    ktReason_Guru_VERR_IEM_ASPECT_NOT_IMPLEMENTED      = ( 'Guru Meditations', 'VERR_IEM_ASPECT_NOT_IMPLEMENTED' );
     357    ktReason_Guru_VINF_EM_TRIPLE_FAULT                 = ( 'Guru Meditations', 'VINF_EM_TRIPLE_FAULT' );
     358    ## @}
     359
     360    def caseClosed(self, oCaseFile):
     361        """
     362        Reports the findings in the case and closes it.
     363        """
     364        #
     365        # Log it and create a dReasonForReasultId we can use below.
     366        #
     367        if len(oCaseFile.dReasonForResultId):
     368            self.vprint('Closing %s with following reasons: %s' % (oCaseFile.sName, oCaseFile.dReasonForResultId,));
     369            dReasonForReasultId = oCaseFile.dReasonForResultId;
     370        elif oCaseFile.tReason is not None:
     371            self.vprint('Closing %s with following reason: %s'  % (oCaseFile.sName, oCaseFile.tReason,));
     372            dReasonForReasultId = { oCaseFile.oTestSet.idTestResult: oCaseFile.tReason, };
     373        else:
     374            self.vprint('Closing %s without a reason ... weird!' % (oCaseFile.sName,));
     375            return False;
     376
     377        #
     378        # Add the test failure reason record(s).
     379        #
     380        for idTestResult, tReason in dReasonForReasultId.items():
     381            oFailureReason = self.oFailureReasonLogic.cachedLookupByNameAndCategory(tReason[1], tReason[0]);
     382            if oFailureReason is not None:
     383                oAdd = TestResultFailureData();
     384                oAdd.initFromValues(idTestResult     = idTestResult,
     385                                    idFailureReason  = oFailureReason.idFailureReason,
     386                                    uidAuthor        = self.uidSelf,
     387                                    idTestSet        = oCaseFile.oTestSet.idTestSet,
     388                                    sComment         = 'Set by $Revision$',); # Handy for reverting later.
     389                if self.oConfig.fRealRun:
     390                    try:
     391                        self.oTestResultFailureLogic.addEntry(oAdd, self.uidSelf, fCommit = True);
     392                    except Exception as oXcpt:
     393                        self.eprint('caseClosed: Exception "%s" while adding reason %s for %s'
     394                                    % (oXcpt, oAdd, oCaseFile.sLongName,));
     395            else:
     396                self.eprint('caseClosed: Cannot locate failure reason: %s / %s' % ( tReason[0], tReason[1],));
     397        return True;
     398
     399
     400    def investigateBadTestBox(self, oCaseFile):
     401        """
     402        Checks out bad-testbox statuses.
     403        """
     404        _ = oCaseFile;
     405        return False;
     406
     407
     408    def investigateVBoxUnitTest(self, oCaseFile):
     409        """
     410        Checks out a VBox unittest problem.
     411        """
     412        _ = oCaseFile;
     413
     414        #
     415        # As a first step we'll just fish out what failed here and report
     416        # the unit test case name as the "reason".  This can mostly be done
     417        # using the TestResultDataEx bits, however in case it timed out and
     418        # got killed we have to fish the test timing out from the logs.
     419        #
     420
     421        #
     422        # Report lone failures on the testcase, multiple failures must be
     423        # reported directly on the failing test (will fix the test result
     424        # listing to collect all of them).
     425        #
     426        return False;
     427
     428
     429    ## Thing we search a main or VM log for to figure out why something went bust.
     430    katSimpleMainAndVmLogReasons = [
     431        # ( Whether to stop on hit, needle, reason tuple ),
     432        ( False, 'GuruMeditation',                                  ktReason_Guru_Generic ),
     433        ( True,  'VERR_IEM_INSTR_NOT_IMPLEMENTED',                  ktReason_Guru_VERR_IEM_INSTR_NOT_IMPLEMENTED ),
     434        ( True,  'VERR_IEM_ASPECT_NOT_IMPLEMENTED',                 ktReason_Guru_VERR_IEM_ASPECT_NOT_IMPLEMENTED ),
     435        ( True,  'VINF_EM_TRIPLE_FAULT',                            ktReason_Guru_VINF_EM_TRIPLE_FAULT ),
     436    ];
     437
     438    def investigateVBoxVMTest(self, oCaseFile, fSingleVM):
     439        """
     440        Checks out a VBox VM test.
     441
     442        This is generic investigation of a test running one or more VMs, like
     443        for example a smoke test or a guest installation test.
     444
     445        The fSingleVM parameter is a hint, which probably won't come in useful.
     446        """
     447        _ = fSingleVM;
     448
     449        #
     450        # Do some quick searches thru the main log to see if there is anything
     451        # immediately incriminating evidence there.
     452        #
     453        sMainLog = oCaseFile.getMainLog();
     454        for fStopOnHit, sNeedle, tReason in self.katSimpleMainAndVmLogReasons:
     455            if sMainLog.find(sNeedle) > 0:
     456                oCaseFile.noteReason(tReason);
     457                if fStopOnHit:
     458                    if oCaseFile.isSingleTestFailure():
     459                        return self.caseClosed(oCaseFile);
     460                    break;
     461
     462        return False;
     463
     464
    211465    def reasoningFailures(self):
    212466        """
    213467        Guess the reason for failures.
    214468        """
    215 
     469        #
     470        # Get a list of failed test sets without any assigned failure reason.
     471        #
     472        aoTestSets = self.oTestSetLogic.fetchFailedSetsWithoutReason(cHoursBack = self.oConfig.cHoursBack, tsNow = self.tsNow);
     473        for oTestSet in aoTestSets:
     474            self.dprint('');
     475            self.dprint('reasoningFailures: Checking out test set #%u, status %s'  % ( oTestSet.idTestSet, oTestSet.enmStatus,))
     476
     477            #
     478            # Open a case file and assign it to the right investigator.
     479            #
     480            (oTree, _ ) = self.oTestResultLogic.fetchResultTree(oTestSet.idTestSet);
     481            oBuild      = BuildDataEx().initFromDbWithId(       self.oDb, oTestSet.idBuild,       oTestSet.tsCreated);
     482            oTestBox    = TestBoxData().initFromDbWithGenId(    self.oDb, oTestSet.idGenTestBox);
     483            oTestGroup  = TestGroupData().initFromDbWithId(     self.oDb, oTestSet.idTestGroup,   oTestSet.tsCreated);
     484            oTestCase   = TestCaseDataEx().initFromDbWithGenId( self.oDb, oTestSet.idGenTestCase, oTestSet.tsConfig);
     485
     486            oCaseFile = VirtualTestSheriffCaseFile(self, oTestSet, oTree, oBuild, oTestBox, oTestGroup, oTestCase);
     487
     488            if oTestSet.enmStatus == TestSetData.ksTestStatus_BadTestBox:
     489                self.dprint('investigateBadTestBox is taking over %s.' % (oCaseFile.sLongName,));
     490                self.investigateBadTestBox(oCaseFile);
     491            elif oCaseFile.isVBoxUnitTest():
     492                self.dprint('investigateVBoxUnitTest is taking over %s.' % (oCaseFile.sLongName,));
     493                self.investigateVBoxUnitTest(oCaseFile);
     494            elif oCaseFile.isVBoxInstallTest():
     495                self.dprint('investigateVBoxVMTest is taking over %s.' % (oCaseFile.sLongName,));
     496                self.investigateVBoxVMTest(oCaseFile, fSingleVM = True);
     497            elif oCaseFile.isVBoxSmokeTest():
     498                self.dprint('investigateVBoxVMTest is taking over %s.' % (oCaseFile.sLongName,));
     499                self.investigateVBoxVMTest(oCaseFile, fSingleVM = False);
     500            else:
     501                self.vprint('reasoningFailures: Unable to classify test set: %s' % (oCaseFile.sLongName,));
    216502        return 0;
    217503
     
    223509        """
    224510        # Database stuff.
    225         self.oDb = TMDatabaseConnection()
    226         self.oResultLogic = TestResultLogic(self.oDb);
    227         self.oTestSetLogic = TestSetLogic(self.oDb);
     511        self.oDb                     = TMDatabaseConnection()
     512        self.oTestResultLogic        = TestResultLogic(self.oDb);
     513        self.oTestSetLogic           = TestSetLogic(self.oDb);
     514        self.oFailureReasonLogic     = FailureReasonLogic(self.oDb);
     515        self.oTestResultFailureLogic = TestResultFailureLogic(self.oDb);
    228516
    229517        # Get a fix on our 'now' before we do anything..
     
    232520
    233521        # If we're suppost to commit anything we need to get our user ID.
    234         rcExit = 0;
    235522        if self.oConfig.fRealRun:
    236523            self.oLogin = UserAccountLogic(self.oDb).tryFetchAccountByLoginName(VirtualTestSheriff.ksLoginName);
     
    240527                self.uidSelf = self.oLogin.uid;
    241528
     529        # Do the stuff.
    242530        if rcExit == 0:
    243             # Do the stuff.
     531            rcExit  = self.selfCheck();
     532        if rcExit == 0:
    244533            rcExit  = self.badTestBoxManagement();
    245534            rcExit2 = self.reasoningFailures();
     
    248537
    249538        # Cleanup.
    250         self.oTestSetLogic = None;
    251         self.oResultLogic = None;
     539        self.oFailureReasonLogic     = None;
     540        self.oTestResultFailureLogic = None;
     541        self.oTestSetLogic           = None;
     542        self.oTestResultLogic        = None;
    252543        self.oDb.close();
    253544        self.oDb = None;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette