VirtualBox

Ignore:
Timestamp:
May 29, 2016 6:54:05 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107564
Message:

Added tables. More readable with high failure volumes.

Location:
trunk/src/VBox/ValidationKit/testmanager/webui
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuiadmintestcase.py

    r61255 r61272  
    3232# Validation Kit imports.
    3333from common                             import utils, webutils;
    34 from testmanager.webui.wuicontentbase   import WuiFormContentBase, WuiListContentBase, WuiTmLink, WuiRawHtml;
     34from testmanager.webui.wuicontentbase   import WuiFormContentBase, WuiListContentBase, WuiContentBase, WuiTmLink, WuiRawHtml;
    3535from testmanager.core.db                import isDbTimestampInfinity;
    3636from testmanager.core.testcase          import TestCaseDataEx, TestCaseData, TestCaseDependencyLogic;
    3737from testmanager.core.globalresource    import GlobalResourceData, GlobalResourceLogic;
     38
     39
     40
     41class WuiTestCaseDetailsLink(WuiTmLink):
     42    """  Test case details link by ID. """
     43
     44    def __init__(self, idTestCase, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False, tsNow = None):
     45        from testmanager.webui.wuiadmin import WuiAdmin;
     46        dParams = {
     47            WuiAdmin.ksParamAction:             WuiAdmin.ksActionTestCaseDetails,
     48            TestCaseData.ksParam_idTestCase:    idTestCase,
     49        };
     50        if tsNow is not None:
     51            dParams[WuiAdmin.ksParamEffectiveDate] = tsNow; ## ??
     52        WuiTmLink.__init__(self, sName, WuiAdmin.ksScriptName, dParams, fBracketed = fBracketed);
     53        self.idTestCase = idTestCase;
     54
    3855
    3956class WuiTestCaseList(WuiListContentBase):
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuicontentbase.py

    r61253 r61272  
    173173    def toHtml(self):
    174174        return self.sHtml;
     175
     176class WuiHtmlKeeper(WuiHtmlBase): # pylint: disable=R0903
     177    """
     178    For keeping a list of elements, concatenating their toHtml output together.
     179    """
     180    def __init__(self, aoInitial = None, sSep = ' '):
     181        WuiHtmlBase.__init__(self);
     182        self.sSep   = sSep;
     183        self.aoKept = [];
     184        if aoInitial is not None:
     185            if isinstance(aoInitial, WuiHtmlBase):
     186                self.aoKept.append(aoInitial);
     187            else:
     188                self.aoKept.extend(aoInitial);
     189
     190    def append(self, oObject):
     191        """ Appends one objects. """
     192        self.aoKept.append(oObject);
     193
     194    def extend(self, aoObjects):
     195        """ Appends a list of objects. """
     196        self.aoKept.extend(aoObjects);
     197
     198    def toHtml(self):
     199        return self.sSep.join(oObj.toHtml() for oObj in self.aoKept);
    175200
    176201class WuiSpanText(WuiRawHtml): # pylint: disable=R0903
     
    205230    ## HTML hex entity string for ksShortDetailsLink.
    206231    ksShortChangeLogLinkHtml = '⎗'
     232    ## The text/symbol for a very short reports link.
     233    ksShortReportLink      = u'\u2397'
     234    ## HTML hex entity string for ksShortReportLink.
     235    ksShortReportLinkHtml  = '⎗'
    207236
    208237
     
    225254        sTs = oTsZulu.strftime('%Y-%m-%d %H:%M:%SZ');
    226255        return unicode(sTs).replace('-', u'\u2011').replace(' ', u'\u00a0');
     256
     257    def getNowTs(self):
     258        """ Gets a database compatible current timestamp from python. See db.dbTimestampPythonNow(). """
     259        return db.dbTimestampPythonNow();
    227260
    228261    def formatIntervalShort(self, oInterval):
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuireport.py

    r61271 r61272  
    3232# Validation Kit imports.
    3333from common                             import webutils;
    34 from testmanager.webui.wuicontentbase   import WuiContentBase, WuiSvnLinkWithTooltip;
     34from testmanager.webui.wuicontentbase   import WuiContentBase, WuiTmLink, WuiSvnLinkWithTooltip;
    3535from testmanager.webui.wuihlpgraph      import WuiHlpGraphDataTable, WuiHlpBarGraph;
     36from testmanager.webui.wuitestresult    import WuiTestSetLink;
     37from testmanager.webui.wuiadmintestcase import WuiTestCaseDetailsLink;
    3638from testmanager.core.report            import ReportModelBase;
     39
     40
     41class WuiReportSummaryLink(WuiTmLink):
     42    """ Generic report summary link. """
     43
     44    def __init__(self, sSubject, aIdSubjects, sName = WuiContentBase.ksShortReportLink,
     45                 tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False):
     46        from testmanager.webui.wuimain import WuiMain;
     47        dParams = {
     48            WuiMain.ksParamAction:                WuiMain.ksActionReportSummary,
     49            WuiMain.ksParamReportSubject:         sSubject,
     50            WuiMain.ksParamReportSubjectIds:      aIdSubjects,
     51        };
     52        if tsNow is not None:
     53            dParams[WuiMain.ksParamEffectiveDate] = tsNow;
     54        if cPeriods is not None:
     55            dParams[WuiMain.ksParamReportPeriods] = cPeriods;
     56        if cPeriods is not None:
     57            dParams[WuiMain.ksParamReportPeriodInHours] = cHoursPerPeriod;
     58        WuiTmLink.__init__(self, sName, WuiMain.ksScriptName, dParams, fBracketed = fBracketed);
    3759
    3860
     
    7799            sTitle = self._oModel.sSubject + ' - ' + sTitle; ## @todo add subject to title in a proper way!
    78100
     101        sReport += '\n\n<!-- HEYYOU: sSubject=%s aidSubjects=%s -->\n\n' % (self._oModel.sSubject, self._oModel.aidSubjects);
    79102        return (sTitle, sReport);
    80103
     
    133156    """
    134157
     158    def _splitSeriesIntoMultipleGraphs(self, aidSorted, cMaxSeriesPerGraph = 8):
     159        """
     160        Splits the ID array into one or more arrays, making sure we don't
     161        have too many series per graph.
     162        Returns array of ID arrays.
     163        """
     164        if len(aidSorted) <= cMaxSeriesPerGraph + 2:
     165            return [aidSorted,];
     166        cGraphs   = len(aidSorted) / cMaxSeriesPerGraph + (len(aidSorted) % cMaxSeriesPerGraph != 0);
     167        cPerGraph = len(aidSorted) / cGraphs + (len(aidSorted) % cGraphs != 0);
     168
     169        aaoRet = [];
     170        cLeft  = len(aidSorted);
     171        iSrc   = 0;
     172        while cLeft > 0:
     173            cThis = cPerGraph;
     174            if cLeft <= cPerGraph + 2:
     175                cThis = cLeft;
     176            elif cLeft <= cPerGraph * 2 + 4:
     177                cThis = cLeft / 2;
     178            aaoRet.append(aidSorted[iSrc : iSrc + cThis]);
     179            iSrc  += cThis;
     180            cLeft -= cThis;
     181        return aaoRet;
     182
    135183    def _formatEdgeOccurenceSubject(self, oTransient):
    136184        """
     
    151199        else:                   sHtml += 'Until ';
    152200        sHtml += WuiSvnLinkWithTooltip(oTransient.iRevision, oTransient.sRepository, fBracketed = 'False').toHtml();
    153         sHtml += u', %s: ' % (self.formatTsShort(oTransient.tsDone),);
     201        sHtml += u', %s: ' % (WuiTestSetLink(oTransient.idTestSet, self.formatTsShort(oTransient.tsDone),
     202                                             fBracketed = False).toHtml(), )
    154203        sHtml += self._formatEdgeOccurenceSubject(oTransient);
    155204        sHtml += u'</li>\n';
     
    160209        Generates the enter and leave lists.
    161210        """
     211        # Skip this if we're looking at builds.
     212        if self._oModel.sSubject in [self._oModel.ksSubBuild,] and len(self._oModel.aidSubjects) in [1, 2]:
     213            return u'';
     214
    162215        sHtml  = u'<h4>Movements:</h4>\n' \
    163216                 u'<ul>\n';
     
    174227
    175228
     229    def _formatSeriesNameForTable(self, oSet, idKey):
     230        """ Formats the series name for the HTML table. """
     231        _ = oSet;
     232        return '<td>%d</td>' % (idKey,);
     233
     234    def _formatRowValueForTable(self, oRow, oPeriod, cColsPerSeries):
     235        """ Formats a row value for the HTML table. """
     236        _ = oPeriod;
     237        if oRow is None:
     238            return u'<td colspan="%d"> </td>' % (cColsPerSeries,);
     239        if cColsPerSeries == 2:
     240            return u'<td align="right">%u%%</td><td align="center">%u / %u</td>' \
     241                   % (oRow.cHits * 100 / oRow.cTotal, oRow.cHits, oRow.cTotal);
     242        return u'<td align="center">%u</td>' % (oRow.cHits,);
     243
     244    def _formatSeriesTotalForTable(self, oSet, idKey, cColsPerSeries):
     245        """ Formats the totals cell for a data series in the HTML table. """
     246        dcTotalPerId = getattr(oSet, 'dcTotalPerId', None);
     247        if cColsPerSeries == 2:
     248            return u'<td align="right">%u%%</td><td align="center">%u/%u</td>' \
     249                   % (oSet.dcHitsPerId[idKey] * 100 / dcTotalPerId[idKey], oSet.dcHitsPerId[idKey], dcTotalPerId[idKey]);
     250        return u'<td align="center">%u</td>' % (oSet.dcHitsPerId[idKey],);
     251
     252    def _generateTableForSet(self, oSet, sColumnName, aidSorted = None, fWithTotals = True, cColsPerSeries = None):
     253        """
     254        Turns the set into a table.
     255
     256        Returns raw html.
     257        """
     258        sHtml  = u'<table class="tmtbl-report-set" width="100%%">\n';
     259        if cColsPerSeries is None:
     260            cColsPerSeries = 2 if hasattr(oSet, 'dcTotalPerId') else 1;
     261
     262        # Header row.
     263        sHtml += u' <tr><thead><th></th><th>%s</th>' % (webutils.escapeElem(sColumnName),)
     264        for oPeriod in reversed(oSet.aoPeriods):
     265            sHtml += u'<th colspan="%d">%s</th>' % (cColsPerSeries, webutils.escapeElem(oPeriod.sDesc),);
     266        if fWithTotals:
     267            sHtml += u'<th colspan="%d">Total</th>' % (cColsPerSeries,);
     268        sHtml += u'</thead></td>\n';
     269
     270        # Each data series.
     271        if aidSorted is None:
     272            aidSorted = oSet.dSubjects.keys();
     273        sHtml += u' <tbody>\n';
     274        for iRow, idKey in enumerate(aidSorted):
     275            sHtml += u'  <tr class="%s">' % ('tmodd' if iRow & 1 else 'tmeven',);
     276            sHtml += u'<td align="left">#%u</td>' % (iRow + 1,);
     277            sHtml += self._formatSeriesNameForTable(oSet, idKey);
     278            for oPeriod in reversed(oSet.aoPeriods):
     279                oRow = oPeriod.dRowsById.get(idKey, None);
     280                sHtml += self._formatRowValueForTable(oRow, oPeriod, cColsPerSeries);
     281            if fWithTotals:
     282                sHtml += self._formatSeriesTotalForTable(oSet, idKey, cColsPerSeries);
     283            sHtml += u' </tr>\n';
     284        sHtml += u' </tbody>\n';
     285        sHtml += u'</table>\n';
     286        return sHtml;
     287
     288
     289
    176290
    177291class WuiReportFailureReasons(WuiReportFailuresBase):
     
    184298                              webutils.escapeElem(oTransient.oReason.sShort),);
    185299
     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
    186307
    187308    def generateReportBody(self):
     
    189310
    190311        #
    191         # Get the data and generate transition list.
     312        # Get the data and sort the data series in descending order of badness.
    192313        #
    193314        oSet = self._oModel.getFailureReasons();
    194         sHtml = self._generateTransitionList(oSet);
     315        aidSorted = 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', aidSorted);
     321        sHtml += self._generateTransitionList(oSet);
    195322
    196323        #
     
    208335        # Generate the graph.
    209336        #
    210         aidSorted = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True);
    211 
    212         asNames = [];
    213         for idReason in aidSorted:
    214             oReason = oSet.dSubjects[idReason];
    215             asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
    216         if fIncludeWithoutReason:
    217             asNames.append('No reason');
    218 
    219         oTable = WuiHlpGraphDataTable('Period', asNames);
    220 
    221         cMax = oSet.cMaxHits;
    222         for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
    223             aiValues = [];
    224 
     337        fGenerateGraph = True;
     338        if fGenerateGraph:
     339            asNames = [];
    225340            for idReason in aidSorted:
    226                 oRow = oPeriod.dRowsById.get(idReason, None);
    227                 iValue = oRow.cHits if oRow is not None else 0;
    228                 aiValues.append(iValue);
    229 
     341                oReason = oSet.dSubjects[idReason];
     342                asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
    230343            if fIncludeWithoutReason:
    231                 aiValues.append(oPeriod.cWithoutReason);
    232                 if oPeriod.cWithoutReason > cMax:
    233                     cMax = oPeriod.cWithoutReason;
    234 
    235             oTable.addRow(oPeriod.sDesc, aiValues);
    236 
    237         oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
    238         oGraph.setRangeMax(max(cMax + 1, 3));
    239         sHtml += oGraph.renderGraph();
    240 
    241         #
    242         # Table form necessary?
    243         #
    244         #sHtml += u'<p>TODO: Show graph content in table form.</p>';
    245 
     344                asNames.append('No reason');
     345
     346            oTable = WuiHlpGraphDataTable('Period', asNames);
     347
     348            cMax = oSet.cMaxHits;
     349            for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
     350                aiValues = [];
     351
     352                for idReason in aidSorted:
     353                    oRow = oPeriod.dRowsById.get(idReason, None);
     354                    iValue = oRow.cHits if oRow is not None else 0;
     355                    aiValues.append(iValue);
     356
     357                if fIncludeWithoutReason:
     358                    aiValues.append(oPeriod.cWithoutReason);
     359                    if oPeriod.cWithoutReason > cMax:
     360                        cMax = oPeriod.cWithoutReason;
     361
     362                oTable.addRow(oPeriod.sDesc, aiValues);
     363
     364            oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
     365            oGraph.setRangeMax(max(cMax + 1, 3));
     366            sHtml += oGraph.renderGraph();
    246367        return sHtml;
    247368
     
    253374
    254375    def _formatEdgeOccurenceSubject(self, oTransient):
    255         return u'%s (#%u)' % ( webutils.escapeElem(oTransient.oTestCase.sName), oTransient.oTestCase.idTestCase,);
    256 
     376        sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oTestCase.sName),);
     377        sHtml += WuiTestCaseDetailsLink(oTransient.oTestCase.idTestCase, fBracketed = False).toHtml();
     378        return sHtml;
     379
     380    def _formatSeriesNameForTable(self, oSet, idKey):
     381        oTestCase = oSet.dSubjects[idKey];
     382        sHtml  = '<td>'
     383        sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName).toHtml();
     384        sHtml += u' ';
     385        sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml();
     386        sHtml += '</td>'
     387        return sHtml;
    257388
    258389    def generateReportBody(self):
    259390        self._sTitle = 'Test Case Failures';
    260391
    261         #
    262         # Get the data and generate transition list.
     392
     393        #
     394        # Get the data and sort the data series in descending order of badness.
    263395        #
    264396        oSet = self._oModel.getTestCaseFailures();
    265         sHtml = self._generateTransitionList(oSet);
     397        if self._oModel.tsNow is not None and False:
     398            # Sort the total.
     399            aidSortedRaw = sorted(oSet.dSubjects,
     400                                  key = lambda idKey: oSet.dcHitsPerId[idKey] * 10000 / oSet.dcTotalPerId[idKey],
     401                                  reverse = True);
     402        else:
     403            # Sort by NOW column.
     404            dTmp = {};
     405            for idKey in oSet.dSubjects:
     406                oRow = oSet.aoPeriods[-1].dRowsById.get(idKey, None);
     407                if oRow is None:    dTmp[idKey] = 0;
     408                else:               dTmp[idKey] = oRow.cHits * 10000 / max(1, oRow.cTotal);
     409            aidSortedRaw = sorted(dTmp, key = lambda idKey: dTmp[idKey], reverse = True);
     410
     411        #
     412        # Generate table and transition list. These are the most useful ones with the current graph machinery.
     413        #
     414        sHtml  = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw);
     415        sHtml += self._generateTransitionList(oSet);
    266416
    267417        #
    268418        # Generate the graph.
    269419        #
    270         aidSorted = sorted(oSet.dSubjects,
    271                            key = lambda idKey: oSet.dcHitsPerId[idKey] * 10000 / oSet.dcTotalPerId[idKey],
    272                            reverse = True);
    273 
    274         asNames = [];
    275         for idKey in aidSorted:
    276             oSubject = oSet.dSubjects[idKey];
    277             asNames.append(oSubject.sName);
    278 
    279         oTable = WuiHlpGraphDataTable('Period', asNames);
    280 
    281         uPctMax = 10;
    282         for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
    283             aiValues = [];
    284             asValues = [];
    285 
    286             for idKey in aidSorted:
    287                 oRow = oPeriod.dRowsById.get(idKey, None);
    288                 if oRow is not None:
    289                     uPct = oRow.cHits * 100 / oRow.cTotal;
    290                     uPctMax = max(uPctMax, uPct);
    291                     aiValues.append(uPct);
    292                     asValues.append('%u%% (%u/%u)' % (uPct, oRow.cHits, oRow.cTotal));
    293                 else:
    294                     aiValues.append(0);
    295                     asValues.append('0');
    296 
    297             oTable.addRow(oPeriod.sDesc, aiValues, asValues);
    298 
    299         if True: # pylint: disable=W0125
    300             aiValues = [];
    301             asValues = [];
    302             for idKey in aidSorted:
    303                 uPct = oSet.dcHitsPerId[idKey] * 100 / oSet.dcTotalPerId[idKey];
    304                 uPctMax = max(uPctMax, uPct);
    305                 aiValues.append(uPct);
    306                 asValues.append('%u%% (%u/%u)' % (uPct, oSet.dcHitsPerId[idKey], oSet.dcTotalPerId[idKey]));
    307             oTable.addRow('Totals', aiValues, asValues);
    308 
    309         oGraph = WuiHlpBarGraph('testcase-failures', oTable, self._oDisp);
    310         oGraph.setRangeMax(uPct + 2);
    311         sHtml += oGraph.renderGraph();
     420        fGenerateGraph = len(aidSortedRaw) <= 6; ## Make this configurable.
     421        if fGenerateGraph:
     422            # Figure the graph width for all of them.
     423            uPctMax = max(oSet.uMaxPct, oSet.cMaxHits * 100 / oSet.cMaxTotal);
     424            uPctMax = max(uPctMax + 2, 10);
     425
     426            for _, aidSorted in enumerate(self._splitSeriesIntoMultipleGraphs(aidSortedRaw, 8)):
     427                asNames = [];
     428                for idKey in aidSorted:
     429                    oSubject = oSet.dSubjects[idKey];
     430                    asNames.append(oSubject.sName);
     431
     432                oTable = WuiHlpGraphDataTable('Period', asNames);
     433
     434                for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
     435                    aiValues = [];
     436                    asValues = [];
     437
     438                    for idKey in aidSorted:
     439                        oRow = oPeriod.dRowsById.get(idKey, None);
     440                        if oRow is not None:
     441                            uPct = oRow.cHits * 100 / oRow.cTotal;
     442                            aiValues.append(uPct);
     443                            asValues.append('%u%% (%u/%u)' % (uPct, oRow.cHits, oRow.cTotal));
     444                        else:
     445                            aiValues.append(0);
     446                            asValues.append('0');
     447
     448                    oTable.addRow(oPeriod.sDesc, aiValues, asValues);
     449
     450                if True: # pylint: disable=W0125
     451                    aiValues = [];
     452                    asValues = [];
     453                    for idKey in aidSorted:
     454                        uPct = oSet.dcHitsPerId[idKey] * 100 / oSet.dcTotalPerId[idKey];
     455                        aiValues.append(uPct);
     456                        asValues.append('%u%% (%u/%u)' % (uPct, oSet.dcHitsPerId[idKey], oSet.dcTotalPerId[idKey]));
     457                    oTable.addRow('Totals', aiValues, asValues);
     458
     459                oGraph = WuiHlpBarGraph('testcase-failures', oTable, self._oDisp);
     460                oGraph.setRangeMax(uPctMax);
     461                sHtml += '<br>\n';
     462                sHtml += oGraph.renderGraph();
    312463
    313464        return sHtml;
  • trunk/src/VBox/ValidationKit/testmanager/webui/wuitestresult.py

    r61267 r61272  
    3030
    3131# Python imports.
     32import datetime;
    3233
    3334# Validation Kit imports.
    3435from testmanager.webui.wuicontentbase           import WuiContentBase, WuiListContentBase, WuiHtmlBase, WuiTmLink, WuiLinkBase, \
    35                                                        WuiSvnLink, WuiSvnLinkWithTooltip, WuiBuildLogLink, WuiRawHtml;
     36                                                       WuiSvnLink, WuiSvnLinkWithTooltip, WuiBuildLogLink, WuiRawHtml, \
     37                                                       WuiHtmlKeeper;
    3638from testmanager.webui.wuimain                  import WuiMain;
    3739from testmanager.webui.wuihlpform               import WuiHlpForm;
     
    3941from testmanager.webui.wuitestresultfailure     import WuiTestResultFailureDetailsLink;
    4042from testmanager.core.failurereason             import FailureReasonData, FailureReasonLogic;
    41 from testmanager.core.report                    import ReportGraphModel;
     43from testmanager.core.report                    import ReportGraphModel, ReportModelBase;
    4244from testmanager.core.testbox                   import TestBoxData;
    4345from testmanager.core.testcase                  import TestCaseData;
     
    4951from testmanager                                import config;
    5052from common                                     import webutils, utils;
     53
     54
     55class WuiTestSetLink(WuiTmLink):
     56    """  Test set link. """
     57
     58    def __init__(self, idTestSet, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False):
     59        WuiTmLink.__init__(self, sName, WuiMain.ksScriptName,
     60                           { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
     61                             TestSetData.ksParam_idTestSet: idTestSet, }, fBracketed = fBracketed);
     62        self.idTestSet = idTestSet;
    5163
    5264
     
    442454        asHtml = []
    443455
     456        from testmanager.webui.wuireport import WuiReportSummaryLink;
     457        tsReportEffectiveDate = None;
     458        if oTestSet.tsDone is not None:
     459            tsReportEffectiveDate = oTestSet.tsDone + datetime.timedelta(days = 4);
     460            if tsReportEffectiveDate >= self.getNowTs():
     461                tsReportEffectiveDate = None;
     462
    444463        # Test result + test set details.
    445464        aoResultRows = [
    446             WuiTmLink(oTestCaseEx.sName, self.oWuiAdmin.ksScriptName,
    447                       { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionTestCaseDetails,
    448                         TestCaseData.ksParam_idTestCase:      oTestCaseEx.idTestCase,
    449                         self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsConfig, },
    450                       fBracketed = False),
     465            WuiHtmlKeeper([ WuiTmLink(oTestCaseEx.sName, self.oWuiAdmin.ksScriptName,
     466                                      { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionTestCaseDetails,
     467                                        TestCaseData.ksParam_idTestCase:      oTestCaseEx.idTestCase,
     468                                        self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsConfig, },
     469                                      fBracketed = False),
     470                            WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCaseEx.idTestCase,
     471                                                 tsNow = tsReportEffectiveDate, fBracketed = False),
     472                          ]),
    451473        ];
    452474        if oTestCaseEx.sDescription is not None and len(oTestCaseEx.sDescription) > 0:
     
    483505
    484506        aoResultRows += [
    485             ( 'Test Group:',    WuiTmLink(oTestGroup.sName, self.oWuiAdmin.ksScriptName,
    486                                           { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionTestGroupDetails,
    487                                             TestGroupData.ksParam_idTestGroup:    oTestGroup.idTestGroup,
    488                                             self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsConfig,  },
    489                                           fBracketed = False) ),
     507            ( 'Test Group:',
     508              WuiHtmlKeeper([ WuiTmLink(oTestGroup.sName, self.oWuiAdmin.ksScriptName,
     509                                        { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionTestGroupDetails,
     510                                          TestGroupData.ksParam_idTestGroup:    oTestGroup.idTestGroup,
     511                                          self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsConfig,  },
     512                                        fBracketed = False),
     513                              WuiReportSummaryLink(ReportModelBase.ksSubTestGroup, oTestGroup.idTestGroup,
     514                                                   tsNow = tsReportEffectiveDate, fBracketed = False),
     515                              ]), ),
    490516        ];
    491517        if oTestVarEx.sTestBoxReqExpr is not None:
     
    508534        if oBuildEx is not None:
    509535            aoBuildRows += [
    510                 WuiTmLink('Build', self.oWuiAdmin.ksScriptName,
    511                           { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionBuildDetails,
    512                             BuildData.ksParam_idBuild:            oBuildEx.idBuild,
    513                             self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsCreated, },
    514                           fBracketed = False),
     536                WuiHtmlKeeper([ WuiTmLink('Build', self.oWuiAdmin.ksScriptName,
     537                                          { self.oWuiAdmin.ksParamAction:         self.oWuiAdmin.ksActionBuildDetails,
     538                                            BuildData.ksParam_idBuild:            oBuildEx.idBuild,
     539                                            self.oWuiAdmin.ksParamEffectiveDate:  oTestSet.tsCreated, },
     540                                          fBracketed = False),
     541                                WuiReportSummaryLink(ReportModelBase.ksSubBuild, oBuildEx.idBuild,
     542                                                     tsNow = tsReportEffectiveDate, fBracketed = False), ]),
    515543            ];
    516544            self._anchorAndAppendBinaries(oBuildEx.sBinaries, aoBuildRows);
     
    558586        # TestBox.
    559587        aoTestBoxRows = [
    560             WuiTmLink(oTestBox.sName, self.oWuiAdmin.ksScriptName,
    561                       { self.oWuiAdmin.ksParamAction:     self.oWuiAdmin.ksActionTestBoxDetails,
    562                         TestBoxData.ksParam_idGenTestBox: oTestSet.idGenTestBox, },
    563                       fBracketed = False),
     588            WuiHtmlKeeper([ WuiTmLink(oTestBox.sName, self.oWuiAdmin.ksScriptName,
     589                                      { self.oWuiAdmin.ksParamAction:     self.oWuiAdmin.ksActionTestBoxDetails,
     590                                        TestBoxData.ksParam_idGenTestBox: oTestSet.idGenTestBox, },
     591                                      fBracketed = False),
     592                            WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestSet.idTestBox,
     593                                                 tsNow = tsReportEffectiveDate, fBracketed = False), ]),
    564594        ];
    565595        if oTestBox.sDescription is not None and len(oTestBox.sDescription) > 0:
     
    756786
    757787        from testmanager.webui.wuiadmin import WuiAdmin;
    758 
     788        from testmanager.webui.wuireport import WuiReportSummaryLink;
    759789
    760790        oValidationKit = None;
     
    842872                        { WuiAdmin.ksParamAction:        WuiAdmin.ksActionTestBoxDetails,
    843873                          TestBoxData.ksParam_idTestBox: oEntry.idTestBox },
    844                         fBracketed = False) ],
     874                        fBracketed = False),
     875              WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oEntry.idTestBox, fBracketed = False), ],
    845876            '%s.%s' % (oEntry.sOs, oEntry.sArch),
    846877            [ WuiTmLink(sTestCaseName, WuiMain.ksScriptName, self._dTestCaseLinkParams, fBracketed = False,
     
    849880                        { WuiAdmin.ksParamAction:          WuiAdmin.ksActionTestCaseDetails,
    850881                          TestCaseData.ksParam_idTestCase: oEntry.idTestCase },
    851                         fBracketed = False), ],
     882                        fBracketed = False),
     883              WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oEntry.idTestCase, fBracketed = False), ],
    852884            oEntry.tsElapsed,
    853885            aoTestSetLinks,
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