VirtualBox

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/webui
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • 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