VirtualBox

Changeset 61286 in vbox for trunk/src


Ignore:
Timestamp:
May 30, 2016 12:22:41 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107578
Message:

wuireport.py,++: Added build box failure report. When requesting details on a testcase (or more), you'll now get a report on the test case variations too. Made links include the period length+count and effective date

Location:
trunk/src/VBox/ValidationKit/testmanager
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testmanager/core/failurecategory.py

    r61270 r61286  
    109109    def __init__(self, oDb):
    110110        ModelLogicBase.__init__(self, oDb)
    111         self.ahCache = None;
     111        self.dCache = None;
    112112
    113113    def fetchForListing(self, iStart, cMaxRows, tsNow):
     
    309309        Raises exception on DB error.
    310310        """
    311         if self.ahCache is None:
    312             self.ahCache = self._oDb.getCache('FailureCategory');
    313 
    314         oEntry = self.ahCache.get(idFailureCategory, None);
     311        if self.dCache is None:
     312            self.dCache = self._oDb.getCache('FailureCategory');
     313
     314        oEntry = self.dCache.get(idFailureCategory, None);
    315315        if oEntry is None:
    316316            self._oDb.execute('SELECT   *\n'
     
    332332            if self._oDb.getRowCount() == 1:
    333333                oEntry = FailureCategoryData().initFromDbRow(self._oDb.fetchOne());
    334                 self.ahCache[idFailureCategory] = oEntry;
     334                self.dCache[idFailureCategory] = oEntry;
    335335        return oEntry;
    336336
  • trunk/src/VBox/ValidationKit/testmanager/core/failurereason.py

    r61284 r61286  
    144144    def __init__(self, oDb):
    145145        ModelLogicBase.__init__(self, oDb)
    146         self.ahCache = None;
    147         self.ahCacheNameAndCat = None;
     146        self.dCache = None;
     147        self.dCacheNameAndCat = None;
    148148        self.oCategoryLogic = None;
    149149        self.oUserAccountLogic = None;
     
    404404    def cachedLookup(self, idFailureReason):
    405405        """
    406         Looks up the most recent FailureReasonDataEx object for uid idFailureReason
    407         an object cache.
     406        Looks up the most recent FailureReasonDataEx object for idFailureReason
     407        via an object cache.
    408408
    409409        Returns a shared FailureReasonData object.  None if not found.
    410410        Raises exception on DB error.
    411411        """
    412         if self.ahCache is None:
    413             self.ahCache = self._oDb.getCache('FailureReasonDataEx');
    414         oEntry = self.ahCache.get(idFailureReason, None);
     412        if self.dCache is None:
     413            self.dCache = self._oDb.getCache('FailureReasonDataEx');
     414        oEntry = self.dCache.get(idFailureReason, None);
    415415        if oEntry is None:
    416416            self._oDb.execute('SELECT   *\n'
     
    434434                oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic,
    435435                                                               self.oUserAccountLogic);
    436                 self.ahCache[idFailureReason] = oEntry;
     436                self.dCache[idFailureReason] = oEntry;
    437437        return oEntry;
    438438
     
    447447        Raises exception on DB error.
    448448        """
    449         if self.ahCacheNameAndCat is None:
    450             self.ahCacheNameAndCat = self._oDb.getCache('FailureReasonDataEx-By-Name-And-Category');
     449        if self.dCacheNameAndCat is None:
     450            self.dCacheNameAndCat = self._oDb.getCache('FailureReasonDataEx-By-Name-And-Category');
    451451        sKey = '%s:::%s' % (sName, sCategory,);
    452         oEntry = self.ahCacheNameAndCat.get(sKey, None);
     452        oEntry = self.dCacheNameAndCat.get(sKey, None);
    453453        if oEntry is None:
    454454            self._oDb.execute('SELECT   *\n'
     
    482482                oEntry = FailureReasonDataEx().initFromDbRowEx(self._oDb.fetchOne(), self.oCategoryLogic,
    483483                                                               self.oUserAccountLogic);
    484                 self.ahCacheNameAndCat[sKey] = oEntry;
     484                self.dCacheNameAndCat[sKey] = oEntry;
    485485                if sName != oEntry.sShort or sCategory != oEntry.oCategory.sShort:
    486486                    sKey2 = '%s:::%s' % (oEntry.sShort, oEntry.oCategory.sShort,);
    487                     self.ahCacheNameAndCat[sKey2] = oEntry;
     487                    self.dCacheNameAndCat[sKey2] = oEntry;
    488488        return oEntry;
    489489
  • trunk/src/VBox/ValidationKit/testmanager/core/report.py

    r61278 r61286  
    3535from testmanager.core.dbobjcache    import DatabaseObjCache;
    3636from testmanager.core.failurereason import FailureReasonLogic;
    37 from testmanager.core.testbox       import TestBoxData;
     37from testmanager.core.testbox       import TestBoxLogic, TestBoxData;
    3838from testmanager.core.testcase      import TestCaseLogic;
     39from testmanager.core.testcaseargs  import TestCaseArgsLogic;
    3940from common                         import constants;
    4041
     
    198199class ReportTransientBase(object):
    199200    """ Details on the test where a problem was first/last seen.  """
    200     def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter):
     201    def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, # pylint: disable=too-many-arguments
     202                 iPeriod, fEnter, idSubject, oSubject):
    201203        self.idBuild            = idBuild;      # Build ID.
    202204        self.iRevision          = iRevision;    # SVN revision for build.
     
    207209        self.iPeriod            = iPeriod;      # Data set period.
    208210        self.fEnter             = fEnter;       # True if enter event, False if leave event.
     211        self.idSubject          = idSubject;
     212        self.oSubject           = oSubject;
    209213
    210214class ReportFailureReasonTransient(ReportTransientBase):
     
    212216    def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone,  # pylint: disable=R0913
    213217                 iPeriod, fEnter, oReason):
    214         ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter);
     218        ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter,
     219                                     oReason.idFailureReason, oReason);
    215220        self.oReason            = oReason;      # FailureReasonDataEx
    216 
    217 class ReportTestCaseFailureTransient(ReportTransientBase):
    218     """ Details on the test where a test case was first/last seen.  """
    219     def __init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone,  # pylint: disable=R0913
    220                  iPeriod, fEnter, oTestCase):
    221         ReportTransientBase.__init__(self, idBuild, iRevision, sRepository, idTestSet, idTestResult, tsDone, iPeriod, fEnter);
    222         self.oTestCase          = oTestCase;      # TestCaseDataEx
    223 
    224221
    225222
     
    246243        self.idFailureReason    = aoRow[0];
    247244        self.oReason            = oReason;      # FailureReasonDataEx
    248 
    249 class ReportTestCaseFailureRow(ReportHitRowWithTotalBase):
    250     """ The account of one test case for a period. """
    251     def __init__(self, aoRow, oTestCase):
    252         ReportHitRowWithTotalBase.__init__(self, aoRow[0], oTestCase, aoRow[1], aoRow[4], aoRow[2], aoRow[3]);
    253245
    254246
     
    369361        ReportPeriodBase.__init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo);
    370362        self.cWithoutReason     = 0;            # Number of failed test sets without any assigned reason.
    371 
    372 class ReportTestCaseFailurePeriod(ReportPeriodWithTotalBase):
    373     """ A period in ReportTestCaseFailureSet. """
    374     def __init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo):
    375         ReportPeriodWithTotalBase.__init__(self, oSet, iPeriod, sDesc, tsFrom, tsTo);
    376363
    377364
     
    513500        ReportPeriodSetBase.__init__(self, 'idFailureReason');
    514501
    515 class ReportTestCaseFailureSet(ReportPeriodSetWithTotalBase):
    516     """ What ReportLazyModel.getTestCaseFailures returns. """
    517     def __init__(self):
    518         ReportPeriodSetWithTotalBase.__init__(self, 'idTestCase');
    519502
    520503
     
    720703        Gets the test case failures of the subject in the specified period.
    721704
    722         Returns a ReportTestCaseFailureSet instance.
    723 
    724         """
    725 
    726         oTestCaseLogic = TestCaseLogic(self._oDb);
     705        Returns a ReportPeriodSetWithTotalBase instance.
     706
     707        """
     708        return self._getSimpleFailures('idTestCase', TestCaseLogic);
     709
     710
     711    def getTestCaseVariationFailures(self):
     712        """
     713        Gets the test case failures of the subject in the specified period.
     714
     715        Returns a ReportPeriodSetWithTotalBase instance.
     716
     717        """
     718        return self._getSimpleFailures('idTestCaseArgs', TestCaseArgsLogic);
     719
     720
     721    def getTestBoxFailures(self):
     722        """
     723        Gets the test box failures of the subject in the specified period.
     724
     725        Returns a ReportPeriodSetWithTotalBase instance.
     726
     727        """
     728        return self._getSimpleFailures('idTestBox', TestBoxLogic);
     729
     730
     731    def _getSimpleFailures(self, sIdColumn, oCacheLogicType, sIdAttr = None):
     732        """
     733        Gets the test box failures of the subject in the specified period.
     734
     735        Returns a ReportPeriodSetWithTotalBase instance.
     736
     737        """
     738
     739        oLogic = oCacheLogicType(self._oDb);
     740        oSet = ReportPeriodSetWithTotalBase(sIdColumn if sIdAttr is None else sIdAttr);
    727741
    728742        # Retrieve the period results.
    729         oSet = ReportTestCaseFailureSet();
    730743        for iPeriod in xrange(self.cPeriods):
    731             self._oDb.execute('SELECT   idTestCase,\n'
     744            self._oDb.execute('SELECT   ' + sIdColumn + ',\n'
    732745                              '         COUNT(CASE WHEN enmStatus >= \'failure\' THEN 1 END),\n'
    733746                              '         MIN(tsDone),\n'
     
    738751                              + self.getExtraWhereExprForPeriod(iPeriod)
    739752                              + self.getExtraSubjectWhereExpr() + '\n'
    740                               'GROUP BY idTestCase\n');
     753                              'GROUP BY ' + sIdColumn + '\n');
    741754            aaoRows = self._oDb.fetchAll()
    742755
    743             oPeriod = ReportTestCaseFailurePeriod(oSet, iPeriod, self.getStraightPeriodDesc(iPeriod),
    744                                                   self.getPeriodStart(iPeriod), self.getPeriodEnd(iPeriod));
     756            oPeriod = ReportPeriodWithTotalBase(oSet, iPeriod, self.getStraightPeriodDesc(iPeriod),
     757                                                self.getPeriodStart(iPeriod), self.getPeriodEnd(iPeriod));
    745758
    746759            for aoRow in aaoRows:
    747                 oTestCase = oTestCaseLogic.cachedLookup(aoRow[0]);
    748                 oPeriodRow = ReportTestCaseFailureRow(aoRow, oTestCase);
    749                 oPeriod.appendRow(oPeriodRow, oTestCase.idTestCase, oTestCase);
     760                oSubject = oLogic.cachedLookup(aoRow[0]);
     761                oPeriodRow = ReportHitRowWithTotalBase(aoRow[0], oSubject, aoRow[1], aoRow[4], aoRow[2], aoRow[3]);
     762                oPeriod.appendRow(oPeriodRow, aoRow[0], oSubject);
    750763
    751764            oSet.appendPeriod(oPeriod);
     
    762775        for iPeriod in xrange(1, self.cPeriods):
    763776            oPeriod = oSet.aoPeriods[iPeriod];
    764             for oTestCase in oPeriod.dFirst.values():
    765                 oSet.aoEnterInfo.append(self._getEdgeTestCaseFailureOccurence(oTestCase, iPeriod, fEnter = True));
     777            for idSubject, oSubject in oPeriod.dFirst.items():
     778                oSet.aoEnterInfo.append(self._getEdgeSimpleFailureOccurence(idSubject, sIdColumn, oSubject,
     779                                                                            iPeriod, fEnter = True));
    766780
    767781        # Ditto for reasons leaving before the last.
    768782        for iPeriod in xrange(self.cPeriods - 1):
    769783            oPeriod = oSet.aoPeriods[iPeriod];
    770             for oTestCase in oPeriod.dLast.values():
    771                 oSet.aoLeaveInfo.append(self._getEdgeTestCaseFailureOccurence(oTestCase, iPeriod, fEnter = False));
     784            for idSubject, oSubject in oPeriod.dLast.items():
     785                oSet.aoLeaveInfo.append(self._getEdgeSimpleFailureOccurence(idSubject, sIdColumn, oSubject,
     786                                                                            iPeriod, fEnter = False));
    772787
    773788        oSet.finalizePass2();
     
    775790        return oSet;
    776791
    777 
    778     def _getEdgeTestCaseFailureOccurence(self, oTestCase, iPeriod, fEnter = True):
     792    def _getEdgeSimpleFailureOccurence(self, idSubject, sIdColumn, oSubject, iPeriod, fEnter = True):
    779793        """
    780794        Helper for the failure reason report that finds the oldest or newest build
     
    784798        is is returned.
    785799
    786         Returns ReportFailureReasonTransient instant.
     800        Returns ReportTransientBase instant.
    787801
    788802        """
     
    797811                          '         Builds,\n'
    798812                          '         BuildCategories' + self.getExtraSubjectTables() + '\n'
    799                           'WHERE    TestSets.idTestCase       = %s\n'
     813                          'WHERE    TestSets.' + sIdColumn + '      = %s\n'
    800814                          '     AND TestSets.idBuild          = Builds.idBuild\n'
    801815                          '     AND TestSets.enmStatus       >= \'failure\'\n'
     
    808822                          '         TestSets.tsCreated ' + sSorting + '\n'
    809823                          'LIMIT 1\n'
    810                           , ( oTestCase.idTestCase, ));
     824                          , ( idSubject, ));
    811825        aoRow = self._oDb.fetchOne();
    812826        if aoRow is None:
    813             return ReportTestCaseFailureTransient(-1, -1, 'internal-error', -1, -1,
    814                                                   self._oDb.getCurrentTimestamp(), oTestCase, iPeriod, fEnter);
    815         return ReportTestCaseFailureTransient(idBuild = aoRow[3], iRevision = aoRow[4], sRepository = aoRow[5],
    816                                               idTestSet = aoRow[1], idTestResult = aoRow[0], tsDone = aoRow[2],
    817                                               oTestCase = oTestCase, iPeriod = iPeriod, fEnter = fEnter);
     827            return ReportTransientBase(-1, -1, 'internal-error', -1, -1, self._oDb.getCurrentTimestamp(),
     828                                       iPeriod, fEnter, idSubject, oSubject);
     829        return ReportTransientBase(idBuild = aoRow[3], iRevision = aoRow[4], sRepository = aoRow[5],
     830                                   idTestSet = aoRow[1], idTestResult = aoRow[0], tsDone = aoRow[2],
     831                                   iPeriod = iPeriod, fEnter = fEnter, idSubject = idSubject, oSubject = oSubject);
     832
    818833
    819834
  • trunk/src/VBox/ValidationKit/testmanager/core/testbox.py

    r61283 r61286  
    279279    def __init__(self, oDb):
    280280        ModelLogicBase.__init__(self, oDb);
     281        self.dCache = None;
    281282
    282283    def tryFetchTestBoxByUuid(self, sTestBoxUuid):
     
    888889
    889890
     891    def cachedLookup(self, idTestBox):
     892        """
     893        Looks up the most recent TestBoxData object for idTestBox via
     894        an object cache.
     895
     896        Returns a shared TestBoxData object.  None if not found.
     897        Raises exception on DB error.
     898        """
     899        if self.dCache is None:
     900            self.dCache = self._oDb.getCache('TestBoxData');
     901        oEntry = self.dCache.get(idTestBox, None);
     902        if oEntry is None:
     903            self._oDb.execute('SELECT   *\n'
     904                              'FROM     TestBoxes\n'
     905                              'WHERE    idTestBox  = %s\n'
     906                              '     AND tsExpire   = \'infinity\'::TIMESTAMP\n'
     907                              , (idTestBox, ));
     908            if self._oDb.getRowCount() == 0:
     909                # Maybe it was deleted, try get the last entry.
     910                self._oDb.execute('SELECT   *\n'
     911                                  'FROM     TestBoxes\n'
     912                                  'WHERE    idTestBox = %s\n'
     913                                  'ORDER BY tsExpire DESC\n'
     914                                  'LIMIT 1\n'
     915                                  , (idTestBox, ));
     916            elif self._oDb.getRowCount() > 1:
     917                raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idTestBox));
     918
     919            if self._oDb.getRowCount() == 1:
     920                aaoRow = self._oDb.fetchOne();
     921                oEntry = TestBoxData().initFromDbRow(aaoRow);
     922                self.dCache[idTestBox] = oEntry;
     923        return oEntry;
     924
     925
     926
    890927    #
    891928    # The virtual test sheriff interface.
  • trunk/src/VBox/ValidationKit/testmanager/core/testcase.py

    r61284 r61286  
    941941    def __init__(self, oDb):
    942942        ModelLogicBase.__init__(self, oDb)
    943         self.ahCache = None;
     943        self.dCache = None;
    944944
    945945    def getAll(self):
     
    13591359    def cachedLookup(self, idTestCase):
    13601360        """
    1361         Looks up the most recent TestCaseDataEx object for uid idTestCase
    1362         an object cache.
     1361        Looks up the most recent TestCaseDataEx object for idTestCase
     1362        via an object cache.
    13631363
    13641364        Returns a shared TestCaseDataEx object.  None if not found.
    13651365        Raises exception on DB error.
    13661366        """
    1367         if self.ahCache is None:
    1368             self.ahCache = self._oDb.getCache('TestCaseDataEx');
    1369         oEntry = self.ahCache.get(idTestCase, None);
     1367        if self.dCache is None:
     1368            self.dCache = self._oDb.getCache('TestCaseDataEx');
     1369        oEntry = self.dCache.get(idTestCase, None);
    13701370        if oEntry is None:
    1371             ##fNeedTsNow = False;
    1372             fNeedTsNow = True;
     1371            fNeedTsNow = False;
    13731372            self._oDb.execute('SELECT   *\n'
    13741373                              'FROM     TestCases\n'
     
    13931392                tsNow  = oEntry.initFromDbRow(aaoRow).tsEffective if fNeedTsNow else None;
    13941393                oEntry.initFromDbRowEx(aaoRow, self._oDb, tsNow);
    1395                 self.ahCache[idTestCase] = oEntry;
     1394                self.dCache[idTestCase] = oEntry;
    13961395        return oEntry;
    13971396
  • trunk/src/VBox/ValidationKit/testmanager/core/testcaseargs.py

    r61262 r61286  
    193193        raise TMExceptionBase('Do not call me: %s' % (aoRow,))
    194194
     195    def initFromDbRowEx(self, aoRow, oDb, tsConfigEff = None, tsRsrcEff = None):
     196        """
     197        Extended version of initFromDbRow that fills in the rest from the database.
     198        """
     199        TestCaseArgsData.initFromDbRow(self, aoRow);
     200
     201        if tsConfigEff is None: tsConfigEff = oDb.getCurrentTimestamp();
     202        if tsRsrcEff is None:   tsRsrcEff   = oDb.getCurrentTimestamp();
     203
     204        self.oTestCase         = TestCaseData().initFromDbWithId(oDb, self.idTestCase, tsConfigEff);
     205        self.aoTestCasePreReqs = TestCaseDependencyLogic(oDb).getTestCaseDeps(self.idTestCase, tsConfigEff);
     206        self.aoGlobalRsrc      = TestCaseGlobalRsrcDepLogic(oDb).getTestCaseDeps(self.idTestCase, tsRsrcEff);
     207
     208        return self;
     209
    195210    def initFromDbWithId(self, oDb, idTestCaseArgs, tsNow = None, sPeriodBack = None):
    196211        _ = oDb; _ = idTestCaseArgs; _ = tsNow; _ = sPeriodBack;
     
    205220        Initialize from the database, given the ID of a row.
    206221        """
    207 
    208222        oDb.execute('SELECT *, CURRENT_TIMESTAMP FROM TestCaseArgs WHERE idGenTestCaseArgs = %s', (idGenTestCaseArgs,));
    209223        aoRow = oDb.fetchOne();
    210         TestCaseArgsData.initFromDbRow(self, aoRow);
    211 
    212         tsNow = aoRow[TestCaseArgsData.kcDbColumns];
    213         if tsConfigEff is None: tsConfigEff = tsNow;
    214         if tsRsrcEff is None:   tsRsrcEff   = tsNow;
    215 
    216         self.oTestCase         = TestCaseData().initFromDbWithId(oDb, self.idTestCase, tsConfigEff);
    217         self.aoTestCasePreReqs = TestCaseDependencyLogic(oDb).getTestCaseDeps(self.idTestCase, tsConfigEff);
    218         self.aoGlobalRsrc      = TestCaseGlobalRsrcDepLogic(oDb).getTestCaseDeps(self.idTestCase, tsRsrcEff);
    219 
    220         return self;
     224        return self.initFromDbRowEx(aoRow, oDb, tsConfigEff, tsRsrcEff);
    221225
    222226    def convertFromParamNull(self):
     
    259263    def __init__(self, oDb):
    260264        ModelLogicBase.__init__(self, oDb);
     265        self.dCache = None;
    261266
    262267
     
    348353        pass
    349354
     355    def cachedLookup(self, idTestCaseArgs):
     356        """
     357        Looks up the most recent TestCaseArgsDataEx object for idTestCaseArg
     358        via in an object cache.
     359
     360        Returns a shared TestCaseArgDataEx object.  None if not found.
     361        Raises exception on DB error.
     362        """
     363        if self.dCache is None:
     364            self.dCache = self._oDb.getCache('TestCaseArgsDataEx');
     365        oEntry = self.dCache.get(idTestCaseArgs, None);
     366        if oEntry is None:
     367            fNeedTsNow = False;
     368            self._oDb.execute('SELECT   *\n'
     369                              'FROM     TestCaseArgs\n'
     370                              'WHERE    idTestCaseArgs = %s\n'
     371                              '     AND tsExpire       = \'infinity\'::TIMESTAMP\n'
     372                              , (idTestCaseArgs, ));
     373            if self._oDb.getRowCount() == 0:
     374                # Maybe it was deleted, try get the last entry.
     375                self._oDb.execute('SELECT   *\n'
     376                                  'FROM     TestCaseArgs\n'
     377                                  'WHERE    idTestCaseArgs = %s\n'
     378                                  'ORDER BY tsExpire DESC\n'
     379                                  'LIMIT 1\n'
     380                                  , (idTestCaseArgs, ));
     381                fNeedTsNow = True;
     382            elif self._oDb.getRowCount() > 1:
     383                raise self._oDb.integrityException('%s infinity rows for %s' % (self._oDb.getRowCount(), idTestCaseArgs));
     384
     385            if self._oDb.getRowCount() == 1:
     386                aaoRow = self._oDb.fetchOne();
     387                oEntry = TestCaseArgsDataEx();
     388                tsNow  = oEntry.initFromDbRow(aaoRow).tsEffective if fNeedTsNow else None;
     389                oEntry.initFromDbRowEx(aaoRow, self._oDb, tsNow, tsNow);
     390                self.dCache[idTestCaseArgs] = oEntry;
     391        return oEntry;
     392
    350393
    351394#
  • trunk/src/VBox/ValidationKit/testmanager/core/useraccount.py

    r61270 r61286  
    121121    def __init__(self, oDb):
    122122        ModelLogicBase.__init__(self, oDb)
    123         self.ahCache = None;
     123        self.dCache = None;
    124124
    125125    def fetchForListing(self, iStart, cMaxRows, tsNow):
     
    232232        Raises exception on DB error.
    233233        """
    234         if self.ahCache is None:
    235             self.ahCache = self._oDb.getCache('UserAccount');
    236 
    237         oUser = self.ahCache.get(uid, None);
     234        if self.dCache is None:
     235            self.dCache = self._oDb.getCache('UserAccount');
     236
     237        oUser = self.dCache.get(uid, None);
    238238        if oUser is None:
    239239            self._oDb.execute('SELECT   *\n'
     
    255255            if self._oDb.getRowCount() == 1:
    256256                oUser = UserAccountData().initFromDbRow(self._oDb.fetchOne());
    257                 self.ahCache[uid] = oUser;
     257                self.dCache[uid] = oUser;
    258258        return oUser;
    259259
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuiadmintestbox.py

    r61220 r61286  
    3535# Validation Kit imports.
    3636from common                             import utils;
    37 from testmanager.webui.wuicontentbase   import WuiListContentWithActionBase, WuiFormContentBase, WuiLinkBase, WuiSvnLink, \
    38                                                WuiTmLink, WuiSpanText, WuiRawHtml;
     37from testmanager.webui.wuicontentbase   import WuiContentBase, WuiListContentWithActionBase, WuiFormContentBase, WuiLinkBase, \
     38                                               WuiSvnLink, WuiTmLink, WuiSpanText, WuiRawHtml;
    3939from testmanager.core.db                import TMDatabaseConnection;
    4040from testmanager.core.schedgroup        import SchedGroupLogic, SchedGroupData;
     
    4242from testmanager.core.testset           import TestSetData;
    4343from testmanager.core.db                import isDbTimestampInfinity;
     44
     45
     46
     47class WuiTestBoxDetailsLink(WuiTmLink):
     48    """  Test box details link by ID. """
     49
     50    def __init__(self, idTestBox, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False, tsNow = None):
     51        from testmanager.webui.wuiadmin import WuiAdmin;
     52        dParams = {
     53            WuiAdmin.ksParamAction:             WuiAdmin.ksActionTestBoxDetails,
     54            TestBoxData.ksParam_idTestBox:      idTestBox,
     55        };
     56        if tsNow is not None:
     57            dParams[WuiAdmin.ksParamEffectiveDate] = tsNow; ## ??
     58        WuiTmLink.__init__(self, sName, WuiAdmin.ksScriptName, dParams, fBracketed = fBracketed);
     59        self.idTestBox = idTestBox;
     60
    4461
    4562
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuimain.py

    r61278 r61286  
    8181    ksActionReportRate                  = 'ReportRate';
    8282    ksActionReportTestCaseFailures      = 'ReportTestCaseFailures';
     83    ksActionReportTestBoxFailures       = 'ReportTestBoxFailures';
    8384    ksActionReportFailureReasons        = 'ReportFailureReasons';
    8485    ksActionGraphWiz                    = 'GraphWiz';
     
    272273        dCurParams = oSrvGlue.getParameters()
    273274        if dCurParams is not None:
    274             asActionUrlExtras = [ self.ksParamItemsPerPage, self.ksParamEffectiveDate, self.ksParamEffectivePeriod, ];
    275             for sExtraParam in asActionUrlExtras:
     275            for sExtraParam in [ self.ksParamItemsPerPage, self.ksParamEffectiveDate, self.ksParamEffectivePeriod, ]:
    276276                if sExtraParam in dCurParams:
    277                     sExtraTimeNav += '&%s' % webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]})
     277                    sExtraTimeNav += '&%s' % (webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]}),)
     278
     279        # Additional URL parameters for reports
     280        sExtraReports = '';
     281        if dCurParams is not None:
     282            for sExtraParam in [ self.ksParamReportPeriods, self.ksParamReportPeriodInHours, self.ksParamEffectiveDate, ]:
     283                if sExtraParam in dCurParams:
     284                    sExtraReports += '&%s' % (webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]}),)
    278285
    279286        # Shorthand to keep within margins.
     
    298305                'Reports',          sActUrlBase + self.ksActionReportSummary,
    299306                [
    300                     [ 'Summary',                  sActUrlBase + self.ksActionReportSummary ],
    301                     [ 'Success Rate',             sActUrlBase + self.ksActionReportRate ],
    302                     [ 'Test Case Failures',       sActUrlBase + self.ksActionReportTestCaseFailures ],
    303                     [ 'Failure Reasons',          sActUrlBase + self.ksActionReportFailureReasons ],
     307                    [ 'Summary',                  sActUrlBase + self.ksActionReportSummary                 + sExtraReports ],
     308                    [ 'Success Rate',             sActUrlBase + self.ksActionReportRate                    + sExtraReports ],
     309                    [ 'Test Case Failures',       sActUrlBase + self.ksActionReportTestCaseFailures        + sExtraReports ],
     310                    [ 'TestBox Failures',         sActUrlBase + self.ksActionReportTestBoxFailures         + sExtraReports ],
     311                    [ 'Failure Reasons',          sActUrlBase + self.ksActionReportFailureReasons          + sExtraReports ],
    304312                ]
    305313            ],
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuireport.py

    r61275 r61286  
    3636from testmanager.webui.wuitestresult    import WuiTestSetLink;
    3737from testmanager.webui.wuiadmintestcase import WuiTestCaseDetailsLink;
     38from testmanager.webui.wuiadmintestbox  import WuiTestBoxDetailsLink;
    3839from testmanager.core.report            import ReportModelBase;
    3940
     
    4344
    4445    def __init__(self, sSubject, aIdSubjects, sName = WuiContentBase.ksShortReportLink,
    45                  tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False):
     46                 tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False, dExtraParams = None):
    4647        from testmanager.webui.wuimain import WuiMain;
    4748        dParams = {
     
    5051            WuiMain.ksParamReportSubjectIds:      aIdSubjects,
    5152        };
     53        if dExtraParams is not None:
     54            dParams.update(dExtraParams);
    5255        if tsNow is not None:
    5356            dParams[WuiMain.ksParamEffectiveDate] = tsNow;
     
    7073        self._fSubReport    = fSubReport;
    7174        self._sTitle        = None;
     75
     76        # Additional URL parameters for reports
     77        self._dExtraParams  = {};
     78        dCurParams = None if oDisp is None else oDisp.getParameters();
     79        if dCurParams is not None:
     80            from testmanager.webui.wuimain import WuiMain;
     81            for sExtraParam in [ WuiMain.ksParamReportPeriods, WuiMain.ksParamReportPeriodInHours,
     82                                 WuiMain.ksParamEffectiveDate, ]:
     83                if sExtraParam in dCurParams:
     84                    self._dExtraParams[sExtraParam] = dCurParams[sExtraParam];
     85
    7286
    7387    def generateNavigator(self, sWhere):
     
    287301
    288302
    289 
    290 
    291 class WuiReportFailureReasons(WuiReportFailuresBase):
    292     """
    293     Generates a report displaying the failure reasons over time.
    294     """
    295 
    296     def _formatEdgeOccurenceSubject(self, oTransient):
    297         return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort),
    298                               webutils.escapeElem(oTransient.oReason.sShort),);
    299 
    300     def _formatSeriesNameForTable(self, oSet, idKey):
    301         oReason = oSet.dSubjects[idKey];
    302         sHtml  = '<td>'
    303         sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),);
    304         sHtml += '</td>'
    305         return sHtml;
    306 
    307 
    308     def generateReportBody(self):
    309         self._sTitle = 'Failure reasons';
    310 
    311         #
    312         # Get the data and sort the data series in descending order of badness.
    313         #
    314         oSet = self._oModel.getFailureReasons();
    315         aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True);
    316 
    317         #
    318         # Generate table and transition list. These are the most useful ones with the current graph machinery.
    319         #
    320         sHtml  = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw);
    321         sHtml += self._generateTransitionList(oSet);
    322 
    323         #
    324         # Check if most of the stuff is without any assign reason, if so, skip
    325         # that part of the graph so it doesn't offset the interesting bits.
    326         #
    327         fIncludeWithoutReason = True;
    328         for oPeriod in reversed(oSet.aoPeriods):
    329             if oPeriod.cWithoutReason > oSet.cMaxHits * 4:
    330                 fIncludeWithoutReason = False;
    331                 sHtml += '<p>Warning: Many failures without assigned reason!</p>\n';
    332                 break;
    333 
    334         #
    335         # Generate the graph.
    336         #
    337         fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable.
    338         if fGenerateGraph:
    339             aidSorted = aidSortedRaw;
    340 
    341             asNames = [];
    342             for idReason in aidSorted:
    343                 oReason = oSet.dSubjects[idReason];
    344                 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
    345             if fIncludeWithoutReason:
    346                 asNames.append('No reason');
    347 
    348             oTable = WuiHlpGraphDataTable('Period', asNames);
    349 
    350             cMax = oSet.cMaxHits;
    351             for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
    352                 aiValues = [];
    353 
    354                 for idReason in aidSorted:
    355                     oRow = oPeriod.dRowsById.get(idReason, None);
    356                     iValue = oRow.cHits if oRow is not None else 0;
    357                     aiValues.append(iValue);
    358 
    359                 if fIncludeWithoutReason:
    360                     aiValues.append(oPeriod.cWithoutReason);
    361                     if oPeriod.cWithoutReason > cMax:
    362                         cMax = oPeriod.cWithoutReason;
    363 
    364                 oTable.addRow(oPeriod.sDesc, aiValues);
    365 
    366             oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
    367             oGraph.setRangeMax(max(cMax + 1, 3));
    368             sHtml += oGraph.renderGraph();
    369         return sHtml;
    370 
    371 
    372 class WuiReportTestCaseFailures(WuiReportFailuresBase):
    373     """
    374     Generates a report displaying the failure reasons over time.
    375     """
    376 
    377     def _formatEdgeOccurenceSubject(self, oTransient):
    378         sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oTestCase.sName),);
    379         sHtml += WuiTestCaseDetailsLink(oTransient.oTestCase.idTestCase, fBracketed = False).toHtml();
    380         return sHtml;
    381 
    382     def _formatSeriesNameForTable(self, oSet, idKey):
    383         oTestCase = oSet.dSubjects[idKey];
    384         sHtml  = '<td>'
    385         sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName).toHtml();
    386         sHtml += u' ';
    387         sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml();
    388         sHtml += '</td>'
    389         return sHtml;
    390 
    391     def generateReportBody(self):
    392         self._sTitle = 'Test Case Failures';
    393 
    394 
    395         #
    396         # Get the data and sort the data series in descending order of badness.
    397         #
    398         oSet = self._oModel.getTestCaseFailures();
     303class WuiReportFailuresWithTotalBase(WuiReportFailuresBase):
     304    """
     305    For ReportPeriodSetWithTotalBase.
     306    """
     307
     308    def _getSortedIds(self, oSet):
     309        """
     310        Get default sorted subject IDs.
     311        """
     312
    399313        if self._oModel.tsNow is not None and False:
    400314            # Sort the total.
     
    410324                else:               dTmp[idKey] = oRow.cHits * 10000 / max(1, oRow.cTotal);
    411325            aidSortedRaw = sorted(dTmp, key = lambda idKey: dTmp[idKey], reverse = True);
    412 
    413         #
    414         # Generate table and transition list. These are the most useful ones with the current graph machinery.
    415         #
    416         sHtml  = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw);
    417         sHtml += self._generateTransitionList(oSet);
    418 
    419         #
    420         # Generate the graph.
    421         #
     326        return aidSortedRaw;
     327
     328    def _generateGraph(self, oSet, sIdBase, aidSortedRaw):
     329        """
     330        Generates graph.
     331        """
     332        sHtml = u'';
    422333        fGenerateGraph = len(aidSortedRaw) <= 6 and len(aidSortedRaw) > 0; ## Make this configurable.
    423334        if fGenerateGraph:
     
    459370                    oTable.addRow('Totals', aiValues, asValues);
    460371
    461                 oGraph = WuiHlpBarGraph('testcase-failures', oTable, self._oDisp);
     372                oGraph = WuiHlpBarGraph(sIdBase, oTable, self._oDisp);
    462373                oGraph.setRangeMax(uPctMax);
    463374                sHtml += '<br>\n';
    464375                sHtml += oGraph.renderGraph();
    465 
     376        return sHtml;
     377
     378
     379
     380class WuiReportFailureReasons(WuiReportFailuresBase):
     381    """
     382    Generates a report displaying the failure reasons over time.
     383    """
     384
     385    def _formatEdgeOccurenceSubject(self, oTransient):
     386        return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort),
     387                              webutils.escapeElem(oTransient.oReason.sShort),);
     388
     389    def _formatSeriesNameForTable(self, oSet, idKey):
     390        oReason = oSet.dSubjects[idKey];
     391        sHtml  = u'<td>';
     392        sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),);
     393        sHtml += u'</td>';
     394        return sHtml;
     395
     396
     397    def generateReportBody(self):
     398        self._sTitle = 'Failure reasons';
     399
     400        #
     401        # Get the data and sort the data series in descending order of badness.
     402        #
     403        oSet = self._oModel.getFailureReasons();
     404        aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True);
     405
     406        #
     407        # Generate table and transition list. These are the most useful ones with the current graph machinery.
     408        #
     409        sHtml  = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw);
     410        sHtml += self._generateTransitionList(oSet);
     411
     412        #
     413        # Check if most of the stuff is without any assign reason, if so, skip
     414        # that part of the graph so it doesn't offset the interesting bits.
     415        #
     416        fIncludeWithoutReason = True;
     417        for oPeriod in reversed(oSet.aoPeriods):
     418            if oPeriod.cWithoutReason > oSet.cMaxHits * 4:
     419                fIncludeWithoutReason = False;
     420                sHtml += '<p>Warning: Many failures without assigned reason!</p>\n';
     421                break;
     422
     423        #
     424        # Generate the graph.
     425        #
     426        fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable.
     427        if fGenerateGraph:
     428            aidSorted = aidSortedRaw;
     429
     430            asNames = [];
     431            for idReason in aidSorted:
     432                oReason = oSet.dSubjects[idReason];
     433                asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
     434            if fIncludeWithoutReason:
     435                asNames.append('No reason');
     436
     437            oTable = WuiHlpGraphDataTable('Period', asNames);
     438
     439            cMax = oSet.cMaxHits;
     440            for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
     441                aiValues = [];
     442
     443                for idReason in aidSorted:
     444                    oRow = oPeriod.dRowsById.get(idReason, None);
     445                    iValue = oRow.cHits if oRow is not None else 0;
     446                    aiValues.append(iValue);
     447
     448                if fIncludeWithoutReason:
     449                    aiValues.append(oPeriod.cWithoutReason);
     450                    if oPeriod.cWithoutReason > cMax:
     451                        cMax = oPeriod.cWithoutReason;
     452
     453                oTable.addRow(oPeriod.sDesc, aiValues);
     454
     455            oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
     456            oGraph.setRangeMax(max(cMax + 1, 3));
     457            sHtml += oGraph.renderGraph();
     458        return sHtml;
     459
     460
     461class WuiReportTestCaseFailures(WuiReportFailuresWithTotalBase):
     462    """
     463    Generates a report displaying the failure reasons over time.
     464    """
     465
     466    def _formatEdgeOccurenceSubject(self, oTransient):
     467        sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
     468        sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
     469        return sHtml;
     470
     471    def _formatSeriesNameForTable(self, oSet, idKey):
     472        oTestCase = oSet.dSubjects[idKey];
     473        sHtml  = u'<td>';
     474        sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName,
     475                                      dExtraParams = self._dExtraParams).toHtml();
     476        sHtml += u' ';
     477        sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml();
     478        sHtml += u'</td>';
     479        return sHtml;
     480
     481    def generateReportBody(self):
     482        self._sTitle = 'Test Case Failures';
     483        oSet = self._oModel.getTestCaseFailures();
     484        aidSortedRaw = self._getSortedIds(oSet);
     485
     486        sHtml  = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw);
     487        sHtml += self._generateTransitionList(oSet);
     488        sHtml += self._generateGraph(oSet, 'testcase-graph', aidSortedRaw);
     489        return sHtml;
     490
     491
     492class WuiReportTestCaseArgsFailures(WuiReportFailuresWithTotalBase):
     493    """
     494    Generates a report displaying the failure reasons over time.
     495    """
     496
     497    @staticmethod
     498    def _formatName(oTestCaseArgs):
     499        if oTestCaseArgs.sSubName is not None and len(oTestCaseArgs.sSubName) > 0:
     500            sName = u'%s / %s'  % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.sSubName, );
     501        else:
     502            sName = u'%s / #%u' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.idTestCaseArgs, );
     503        return sName;
     504
     505    def _formatEdgeOccurenceSubject(self, oTransient):
     506        sHtml  = u'%s ' % ( webutils.escapeElem(self._formatName(oTransient.oSubject)),);
     507        sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
     508        return sHtml;
     509
     510    def _formatSeriesNameForTable(self, oSet, idKey):
     511        oTestCaseArgs = oSet.dSubjects[idKey];
     512        sHtml  = u'<td>';
     513        sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCaseArgs, oTestCaseArgs.idTestCaseArgs,
     514                                      sName = self._formatName(oTestCaseArgs), dExtraParams = self._dExtraParams).toHtml();
     515        sHtml += u' ';
     516        sHtml += WuiTestCaseDetailsLink(oTestCaseArgs.idTestCase).toHtml();
     517        sHtml += u'</td>';
     518        return sHtml;
     519
     520    def generateReportBody(self):
     521        self._sTitle = 'Test Case Variation Failures';
     522        oSet = self._oModel.getTestCaseVariationFailures();
     523        aidSortedRaw = self._getSortedIds(oSet);
     524
     525        sHtml  = self._generateTableForSet(oSet, 'Test Case Variations', aidSortedRaw);
     526        sHtml += self._generateTransitionList(oSet);
     527        sHtml += self._generateGraph(oSet, 'testcasearg-graph', aidSortedRaw);
     528        return sHtml;
     529
     530
     531
     532class WuiReportTestBoxFailures(WuiReportFailuresWithTotalBase):
     533    """
     534    Generates a report displaying the failure reasons over time.
     535    """
     536
     537    def _formatEdgeOccurenceSubject(self, oTransient):
     538        sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
     539        sHtml += WuiTestBoxDetailsLink(oTransient.oSubject.idTestBox, fBracketed = False).toHtml();
     540        return sHtml;
     541
     542    def _formatSeriesNameForTable(self, oSet, idKey):
     543        oTestBox = oSet.dSubjects[idKey];
     544        sHtml  = u'<td>';
     545        sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestBox.idTestBox, sName = oTestBox.sName,
     546                                      dExtraParams = self._dExtraParams).toHtml();
     547        sHtml += u' ';
     548        sHtml += WuiTestBoxDetailsLink(oTestBox.idTestBox).toHtml();
     549        sHtml += u'</td>';
     550        return sHtml;
     551
     552    def generateReportBody(self):
     553        self._sTitle = 'Test Box Failures';
     554        oSet = self._oModel.getTestBoxFailures();
     555        aidSortedRaw = self._getSortedIds(oSet);
     556
     557        sHtml  = self._generateTableForSet(oSet, 'Test Boxes', aidSortedRaw);
     558        sHtml += self._generateTransitionList(oSet);
     559        sHtml += self._generateGraph(oSet, 'testbox-graph', aidSortedRaw);
    466560        return sHtml;
    467561
     
    477571             % (self._oModel.sSubject, self._oModel.aidSubjects,);
    478572
    479         oSuccessRate      = WuiReportSuccessRate(     self._oModel, self._dParams, fSubReport = True,
    480                                                       fnDPrint = self._fnDPrint, oDisp = self._oDisp);
    481         oTestCaseFailures = WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True,
    482                                                       fnDPrint = self._fnDPrint, oDisp = self._oDisp);
    483         oFailureReasons   = WuiReportFailureReasons(  self._oModel, self._dParams, fSubReport = True,
    484                                                       fnDPrint = self._fnDPrint, oDisp = self._oDisp);
    485         for oReport in [oSuccessRate, oTestCaseFailures, oFailureReasons, ]:
     573        aoReports = [];
     574
     575        aoReports.append(WuiReportSuccessRate(     self._oModel, self._dParams, fSubReport = True,
     576                                                   fnDPrint = self._fnDPrint, oDisp = self._oDisp));
     577        aoReports.append(WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True,
     578                                                   fnDPrint = self._fnDPrint, oDisp = self._oDisp));
     579        if self._oModel.sSubject == ReportModelBase.ksSubTestCase:
     580            aoReports.append(WuiReportTestCaseArgsFailures(self._oModel, self._dParams, fSubReport = True,
     581                                                           fnDPrint = self._fnDPrint, oDisp = self._oDisp));
     582        aoReports.append(WuiReportTestBoxFailures( self._oModel, self._dParams, fSubReport = True,
     583                                                   fnDPrint = self._fnDPrint, oDisp = self._oDisp));
     584        aoReports.append(WuiReportFailureReasons(  self._oModel, self._dParams, fSubReport = True,
     585                                                   fnDPrint = self._fnDPrint, oDisp = self._oDisp));
     586
     587        for oReport in aoReports:
    486588            (sTitle, sContent) = oReport.show();
    487589            sHtml += '<br>'; # drop this layout hack
Note: See TracChangeset for help on using the changeset viewer.

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