VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuireport.py@ 61291

Last change on this file since 61291 was 61291, checked in by vboxsync, 9 years ago

arg. bugs. sorting indicator.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.9 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuireport.py 61291 2016-05-30 12:57:40Z vboxsync $
3
4"""
5Test Manager WUI - Reports.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2015 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 61291 $"
30
31
32# Validation Kit imports.
33from common import webutils;
34from testmanager.webui.wuicontentbase import WuiContentBase, WuiTmLink, WuiSvnLinkWithTooltip;
35from testmanager.webui.wuihlpgraph import WuiHlpGraphDataTable, WuiHlpBarGraph;
36from testmanager.webui.wuitestresult import WuiTestSetLink;
37from testmanager.webui.wuiadmintestcase import WuiTestCaseDetailsLink;
38from testmanager.webui.wuiadmintestbox import WuiTestBoxDetailsLink;
39from testmanager.core.report import ReportModelBase;
40
41
42class WuiReportSummaryLink(WuiTmLink):
43 """ Generic report summary link. """
44
45 def __init__(self, sSubject, aIdSubjects, sName = WuiContentBase.ksShortReportLink,
46 tsNow = None, cPeriods = None, cHoursPerPeriod = None, fBracketed = False, dExtraParams = None):
47 from testmanager.webui.wuimain import WuiMain;
48 dParams = {
49 WuiMain.ksParamAction: WuiMain.ksActionReportSummary,
50 WuiMain.ksParamReportSubject: sSubject,
51 WuiMain.ksParamReportSubjectIds: aIdSubjects,
52 };
53 if dExtraParams is not None:
54 dParams.update(dExtraParams);
55 if tsNow is not None:
56 dParams[WuiMain.ksParamEffectiveDate] = tsNow;
57 if cPeriods is not None:
58 dParams[WuiMain.ksParamReportPeriods] = cPeriods;
59 if cPeriods is not None:
60 dParams[WuiMain.ksParamReportPeriodInHours] = cHoursPerPeriod;
61 WuiTmLink.__init__(self, sName, WuiMain.ksScriptName, dParams, fBracketed = fBracketed);
62
63
64class WuiReportBase(WuiContentBase):
65 """
66 Base class for the reports.
67 """
68
69 def __init__(self, oModel, dParams, fSubReport = False, fnDPrint = None, oDisp = None):
70 WuiContentBase.__init__(self, fnDPrint = fnDPrint, oDisp = oDisp);
71 self._oModel = oModel;
72 self._dParams = dParams;
73 self._fSubReport = fSubReport;
74 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
86
87 def generateNavigator(self, sWhere):
88 """
89 Generates the navigator (manipulate _dParams).
90 Returns HTML.
91 """
92 assert sWhere == 'top' or sWhere == 'bottom';
93
94 return '';
95
96 def generateReportBody(self):
97 """
98 This is overridden by the child class to generate the report.
99 Returns HTML.
100 """
101 return '<h3>Must override generateReportBody!</h3>';
102
103 def show(self):
104 """
105 Generate the report.
106 Returns (sTitle, HTML).
107 """
108
109 sTitle = self._sTitle if self._sTitle is not None else type(self).__name__;
110 sReport = self.generateReportBody();
111 if not self._fSubReport:
112 sReport = self.generateNavigator('top') + sReport + self.generateNavigator('bottom');
113 sTitle = self._oModel.sSubject + ' - ' + sTitle; ## @todo add subject to title in a proper way!
114
115 sReport += '\n\n<!-- HEYYOU: sSubject=%s aidSubjects=%s -->\n\n' % (self._oModel.sSubject, self._oModel.aidSubjects);
116 return (sTitle, sReport);
117
118
119class WuiReportSuccessRate(WuiReportBase):
120 """
121 Generates a report displaying the success rate over time.
122 """
123
124 def generateReportBody(self):
125 self._sTitle = 'Success rate';
126
127 adPeriods = self._oModel.getSuccessRates();
128
129 sReport = '';
130
131 oTable = WuiHlpGraphDataTable('Period', [ 'Succeeded', 'Skipped', 'Failed' ]);
132
133 #for i in range(len(adPeriods) - 1, -1, -1):
134 for i, dStatuses in enumerate(adPeriods):
135 cSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] + dStatuses[ReportModelBase.ksTestStatus_Skipped];
136 cTotal = cSuccess + dStatuses[ReportModelBase.ksTestStatus_Failure];
137 sPeriod = self._oModel.getPeriodDesc(i);
138 if cTotal > 0:
139 iPctSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] * 100 / cTotal;
140 iPctSkipped = dStatuses[ReportModelBase.ksTestStatus_Skipped] * 100 / cTotal;
141 iPctFailure = dStatuses[ReportModelBase.ksTestStatus_Failure] * 100 / cTotal;
142 oTable.addRow(sPeriod, [ iPctSuccess, iPctSkipped, iPctFailure ],
143 [ '%s%% (%d)' % (iPctSuccess, dStatuses[ReportModelBase.ksTestStatus_Success]),
144 '%s%% (%d)' % (iPctSkipped, dStatuses[ReportModelBase.ksTestStatus_Skipped]),
145 '%s%% (%d)' % (iPctFailure, dStatuses[ReportModelBase.ksTestStatus_Failure]), ]);
146 else:
147 oTable.addRow(sPeriod, [ 0, 0, 0 ], [ '0%', '0%', '0%' ]);
148
149 cTotalNow = adPeriods[0][ReportModelBase.ksTestStatus_Success];
150 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Skipped];
151 cSuccessNow = cTotalNow;
152 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Failure];
153 sReport += '<p>Current success rate: ';
154 if cTotalNow > 0:
155 sReport += '%s%% (thereof %s%% skipped)</p>\n' \
156 % ( cSuccessNow * 100 / cTotalNow, adPeriods[0][ReportModelBase.ksTestStatus_Skipped] * 100 / cTotalNow);
157 else:
158 sReport += 'N/A</p>\n'
159
160 oGraph = WuiHlpBarGraph('success-rate', oTable, self._oDisp);
161 oGraph.setRangeMax(100);
162 sReport += oGraph.renderGraph();
163
164 return sReport;
165
166
167class WuiReportFailuresBase(WuiReportBase):
168 """
169 Common parent of WuiReportFailureReasons and WuiReportTestCaseFailures.
170 """
171
172 def _splitSeriesIntoMultipleGraphs(self, aidSorted, cMaxSeriesPerGraph = 8):
173 """
174 Splits the ID array into one or more arrays, making sure we don't
175 have too many series per graph.
176 Returns array of ID arrays.
177 """
178 if len(aidSorted) <= cMaxSeriesPerGraph + 2:
179 return [aidSorted,];
180 cGraphs = len(aidSorted) / cMaxSeriesPerGraph + (len(aidSorted) % cMaxSeriesPerGraph != 0);
181 cPerGraph = len(aidSorted) / cGraphs + (len(aidSorted) % cGraphs != 0);
182
183 aaoRet = [];
184 cLeft = len(aidSorted);
185 iSrc = 0;
186 while cLeft > 0:
187 cThis = cPerGraph;
188 if cLeft <= cPerGraph + 2:
189 cThis = cLeft;
190 elif cLeft <= cPerGraph * 2 + 4:
191 cThis = cLeft / 2;
192 aaoRet.append(aidSorted[iSrc : iSrc + cThis]);
193 iSrc += cThis;
194 cLeft -= cThis;
195 return aaoRet;
196
197 def _formatEdgeOccurenceSubject(self, oTransient):
198 """
199 Worker for _formatEdgeOccurence that child classes overrides to format
200 their type of subject data in the best possible way.
201 """
202 _ = oTransient;
203 assert False;
204 return '';
205
206 def _formatEdgeOccurence(self, oTransient):
207 """
208 Helper for formatting the transients.
209 oTransient is of type ReportFailureReasonTransient or ReportTestCaseFailureTransient.
210 """
211 sHtml = u'<li>';
212 if oTransient.fEnter: sHtml += 'Since ';
213 else: sHtml += 'Until ';
214 sHtml += WuiSvnLinkWithTooltip(oTransient.iRevision, oTransient.sRepository, fBracketed = 'False').toHtml();
215 sHtml += u', %s: ' % (WuiTestSetLink(oTransient.idTestSet, self.formatTsShort(oTransient.tsDone),
216 fBracketed = False).toHtml(), )
217 sHtml += self._formatEdgeOccurenceSubject(oTransient);
218 sHtml += u'</li>\n';
219 return sHtml;
220
221 def _generateTransitionList(self, oSet):
222 """
223 Generates the enter and leave lists.
224 """
225 # Skip this if we're looking at builds.
226 if self._oModel.sSubject in [self._oModel.ksSubBuild,] and len(self._oModel.aidSubjects) in [1, 2]:
227 return u'';
228
229 sHtml = u'<h4>Movements:</h4>\n' \
230 u'<ul>\n';
231 if len(oSet.aoEnterInfo) == 0 and len(oSet.aoLeaveInfo) == 0:
232 sHtml += u'<li>No changes</li>\n';
233 else:
234 for oTransient in oSet.aoEnterInfo:
235 sHtml += self._formatEdgeOccurence(oTransient);
236 for oTransient in oSet.aoLeaveInfo:
237 sHtml += self._formatEdgeOccurence(oTransient);
238 sHtml += u'</ul>\n';
239
240 return sHtml;
241
242
243 def _formatSeriesNameForTable(self, oSet, idKey):
244 """ Formats the series name for the HTML table. """
245 _ = oSet;
246 return '<td>%d</td>' % (idKey,);
247
248 def _formatRowValueForTable(self, oRow, oPeriod, cColsPerSeries):
249 """ Formats a row value for the HTML table. """
250 _ = oPeriod;
251 if oRow is None:
252 return u'<td colspan="%d"> </td>' % (cColsPerSeries,);
253 if cColsPerSeries == 2:
254 return u'<td align="right">%u%%</td><td align="center">%u / %u</td>' \
255 % (oRow.cHits * 100 / oRow.cTotal, oRow.cHits, oRow.cTotal);
256 return u'<td align="center">%u</td>' % (oRow.cHits,);
257
258 def _formatSeriesTotalForTable(self, oSet, idKey, cColsPerSeries):
259 """ Formats the totals cell for a data series in the HTML table. """
260 dcTotalPerId = getattr(oSet, 'dcTotalPerId', None);
261 if cColsPerSeries == 2:
262 return u'<td align="right">%u%%</td><td align="center">%u/%u</td>' \
263 % (oSet.dcHitsPerId[idKey] * 100 / dcTotalPerId[idKey], oSet.dcHitsPerId[idKey], dcTotalPerId[idKey]);
264 return u'<td align="center">%u</td>' % (oSet.dcHitsPerId[idKey],);
265
266 def _generateTableForSet(self, oSet, sColumnName, aidSorted = None, iSortColumn = 0,
267 fWithTotals = True, cColsPerSeries = None):
268 """
269 Turns the set into a table.
270
271 Returns raw html.
272 """
273 sHtml = u'<table class="tmtbl-report-set" width="100%%">\n';
274 if cColsPerSeries is None:
275 cColsPerSeries = 2 if hasattr(oSet, 'dcTotalPerId') else 1;
276
277 # Header row.
278 sHtml += u' <tr><thead><th></th><th>%s</th>' % (webutils.escapeElem(sColumnName),)
279 for iPeriod, oPeriod in enumerate(reversed(oSet.aoPeriods)):
280 sHtml += u'<th colspan="%d">%s%s</th>' % ( cColsPerSeries, webutils.escapeElem(oPeriod.sDesc),
281 '&#x25bc;' if iPeriod == iSortColumn else '');
282 if fWithTotals:
283 sHtml += u'<th colspan="%d">Total%s</th>' % (cColsPerSeries,
284 '&#x25bc;' if iSortColumn == len(oSet.aoPeriods) else '');
285 sHtml += u'</thead></td>\n';
286
287 # Each data series.
288 if aidSorted is None:
289 aidSorted = oSet.dSubjects.keys();
290 sHtml += u' <tbody>\n';
291 for iRow, idKey in enumerate(aidSorted):
292 sHtml += u' <tr class="%s">' % ('tmodd' if iRow & 1 else 'tmeven',);
293 sHtml += u'<td align="left">#%u</td>' % (iRow + 1,);
294 sHtml += self._formatSeriesNameForTable(oSet, idKey);
295 for oPeriod in reversed(oSet.aoPeriods):
296 oRow = oPeriod.dRowsById.get(idKey, None);
297 sHtml += self._formatRowValueForTable(oRow, oPeriod, cColsPerSeries);
298 if fWithTotals:
299 sHtml += self._formatSeriesTotalForTable(oSet, idKey, cColsPerSeries);
300 sHtml += u' </tr>\n';
301 sHtml += u' </tbody>\n';
302 sHtml += u'</table>\n';
303 return sHtml;
304
305
306class WuiReportFailuresWithTotalBase(WuiReportFailuresBase):
307 """
308 For ReportPeriodSetWithTotalBase.
309 """
310
311 def _getSortedIds(self, oSet, fByTotal = None):
312 """
313 Get default sorted subject IDs and which column.
314 """
315
316 if fByTotal is None:
317 fByTotal = oSet.cMaxTotal < 10;
318
319 if fByTotal is True:
320 # Sort the total.
321 aidSortedRaw = sorted(oSet.dSubjects,
322 key = lambda idKey: oSet.dcHitsPerId[idKey] * 10000 / oSet.dcTotalPerId[idKey],
323 reverse = True);
324 iColumn = len(oSet.aoPeriods);
325 else:
326 # Sort by NOW column.
327 dTmp = {};
328 for idKey in oSet.dSubjects:
329 oRow = oSet.aoPeriods[-1].dRowsById.get(idKey, None);
330 if oRow is None: dTmp[idKey] = 0;
331 else: dTmp[idKey] = oRow.cHits * 10000 / max(1, oRow.cTotal);
332 aidSortedRaw = sorted(dTmp, key = lambda idKey: dTmp[idKey], reverse = True);
333 iColumn = 0;
334 return (aidSortedRaw, iColumn);
335
336 def _generateGraph(self, oSet, sIdBase, aidSortedRaw):
337 """
338 Generates graph.
339 """
340 sHtml = u'';
341 fGenerateGraph = len(aidSortedRaw) <= 6 and len(aidSortedRaw) > 0; ## Make this configurable.
342 if fGenerateGraph:
343 # Figure the graph width for all of them.
344 uPctMax = max(oSet.uMaxPct, oSet.cMaxHits * 100 / oSet.cMaxTotal);
345 uPctMax = max(uPctMax + 2, 10);
346
347 for _, aidSorted in enumerate(self._splitSeriesIntoMultipleGraphs(aidSortedRaw, 8)):
348 asNames = [];
349 for idKey in aidSorted:
350 oSubject = oSet.dSubjects[idKey];
351 asNames.append(oSubject.sName);
352
353 oTable = WuiHlpGraphDataTable('Period', asNames);
354
355 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
356 aiValues = [];
357 asValues = [];
358
359 for idKey in aidSorted:
360 oRow = oPeriod.dRowsById.get(idKey, None);
361 if oRow is not None:
362 uPct = oRow.cHits * 100 / oRow.cTotal;
363 aiValues.append(uPct);
364 asValues.append('%u%% (%u/%u)' % (uPct, oRow.cHits, oRow.cTotal));
365 else:
366 aiValues.append(0);
367 asValues.append('0');
368
369 oTable.addRow(oPeriod.sDesc, aiValues, asValues);
370
371 if True: # pylint: disable=W0125
372 aiValues = [];
373 asValues = [];
374 for idKey in aidSorted:
375 uPct = oSet.dcHitsPerId[idKey] * 100 / oSet.dcTotalPerId[idKey];
376 aiValues.append(uPct);
377 asValues.append('%u%% (%u/%u)' % (uPct, oSet.dcHitsPerId[idKey], oSet.dcTotalPerId[idKey]));
378 oTable.addRow('Totals', aiValues, asValues);
379
380 oGraph = WuiHlpBarGraph(sIdBase, oTable, self._oDisp);
381 oGraph.setRangeMax(uPctMax);
382 sHtml += '<br>\n';
383 sHtml += oGraph.renderGraph();
384 return sHtml;
385
386
387
388class WuiReportFailureReasons(WuiReportFailuresBase):
389 """
390 Generates a report displaying the failure reasons over time.
391 """
392
393 def _formatEdgeOccurenceSubject(self, oTransient):
394 return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort),
395 webutils.escapeElem(oTransient.oReason.sShort),);
396
397 def _formatSeriesNameForTable(self, oSet, idKey):
398 oReason = oSet.dSubjects[idKey];
399 sHtml = u'<td>';
400 sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),);
401 sHtml += u'</td>';
402 return sHtml;
403
404
405 def generateReportBody(self):
406 self._sTitle = 'Failure reasons';
407
408 #
409 # Get the data and sort the data series in descending order of badness.
410 #
411 oSet = self._oModel.getFailureReasons();
412 aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True);
413
414 #
415 # Generate table and transition list. These are the most useful ones with the current graph machinery.
416 #
417 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw, len(oSet.aoPeriods));
418 sHtml += self._generateTransitionList(oSet);
419
420 #
421 # Check if most of the stuff is without any assign reason, if so, skip
422 # that part of the graph so it doesn't offset the interesting bits.
423 #
424 fIncludeWithoutReason = True;
425 for oPeriod in reversed(oSet.aoPeriods):
426 if oPeriod.cWithoutReason > oSet.cMaxHits * 4:
427 fIncludeWithoutReason = False;
428 sHtml += '<p>Warning: Many failures without assigned reason!</p>\n';
429 break;
430
431 #
432 # Generate the graph.
433 #
434 fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable.
435 if fGenerateGraph:
436 aidSorted = aidSortedRaw;
437
438 asNames = [];
439 for idReason in aidSorted:
440 oReason = oSet.dSubjects[idReason];
441 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
442 if fIncludeWithoutReason:
443 asNames.append('No reason');
444
445 oTable = WuiHlpGraphDataTable('Period', asNames);
446
447 cMax = oSet.cMaxHits;
448 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
449 aiValues = [];
450
451 for idReason in aidSorted:
452 oRow = oPeriod.dRowsById.get(idReason, None);
453 iValue = oRow.cHits if oRow is not None else 0;
454 aiValues.append(iValue);
455
456 if fIncludeWithoutReason:
457 aiValues.append(oPeriod.cWithoutReason);
458 if oPeriod.cWithoutReason > cMax:
459 cMax = oPeriod.cWithoutReason;
460
461 oTable.addRow(oPeriod.sDesc, aiValues);
462
463 oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
464 oGraph.setRangeMax(max(cMax + 1, 3));
465 sHtml += oGraph.renderGraph();
466 return sHtml;
467
468
469class WuiReportTestCaseFailures(WuiReportFailuresWithTotalBase):
470 """
471 Generates a report displaying the failure reasons over time.
472 """
473
474 def _formatEdgeOccurenceSubject(self, oTransient):
475 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
476 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
477 return sHtml;
478
479 def _formatSeriesNameForTable(self, oSet, idKey):
480 oTestCase = oSet.dSubjects[idKey];
481 sHtml = u'<td>';
482 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName,
483 dExtraParams = self._dExtraParams).toHtml();
484 sHtml += u' ';
485 sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml();
486 sHtml += u'</td>';
487 return sHtml;
488
489 def generateReportBody(self):
490 self._sTitle = 'Test Case Failures';
491 oSet = self._oModel.getTestCaseFailures();
492 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
493
494 sHtml = self._generateTableForSet(oSet, 'Test Cases', aidSortedRaw, iSortColumn);
495 sHtml += self._generateTransitionList(oSet);
496 sHtml += self._generateGraph(oSet, 'testcase-graph', aidSortedRaw);
497 return sHtml;
498
499
500class WuiReportTestCaseArgsFailures(WuiReportFailuresWithTotalBase):
501 """
502 Generates a report displaying the failure reasons over time.
503 """
504
505 @staticmethod
506 def _formatName(oTestCaseArgs):
507 if oTestCaseArgs.sSubName is not None and len(oTestCaseArgs.sSubName) > 0:
508 sName = u'%s / %s' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.sSubName, );
509 else:
510 sName = u'%s / #%u' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.idTestCaseArgs, );
511 return sName;
512
513 def _formatEdgeOccurenceSubject(self, oTransient):
514 sHtml = u'%s ' % ( webutils.escapeElem(self._formatName(oTransient.oSubject)),);
515 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
516 return sHtml;
517
518 def _formatSeriesNameForTable(self, oSet, idKey):
519 oTestCaseArgs = oSet.dSubjects[idKey];
520 sHtml = u'<td>';
521 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCaseArgs, oTestCaseArgs.idTestCaseArgs,
522 sName = self._formatName(oTestCaseArgs), dExtraParams = self._dExtraParams).toHtml();
523 sHtml += u' ';
524 sHtml += WuiTestCaseDetailsLink(oTestCaseArgs.idTestCase).toHtml();
525 sHtml += u'</td>';
526 return sHtml;
527
528 def generateReportBody(self):
529 self._sTitle = 'Test Case Variation Failures';
530 oSet = self._oModel.getTestCaseVariationFailures();
531 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
532
533 sHtml = self._generateTableForSet(oSet, 'Test Case Variations', aidSortedRaw, iSortColumn);
534 sHtml += self._generateTransitionList(oSet);
535 sHtml += self._generateGraph(oSet, 'testcasearg-graph', aidSortedRaw);
536 return sHtml;
537
538
539
540class WuiReportTestBoxFailures(WuiReportFailuresWithTotalBase):
541 """
542 Generates a report displaying the failure reasons over time.
543 """
544
545 def _formatEdgeOccurenceSubject(self, oTransient):
546 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
547 sHtml += WuiTestBoxDetailsLink(oTransient.oSubject.idTestBox, fBracketed = False).toHtml();
548 return sHtml;
549
550 def _formatSeriesNameForTable(self, oSet, idKey):
551 oTestBox = oSet.dSubjects[idKey];
552 sHtml = u'<td>';
553 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestBox.idTestBox, sName = oTestBox.sName,
554 dExtraParams = self._dExtraParams).toHtml();
555 sHtml += u' ';
556 sHtml += WuiTestBoxDetailsLink(oTestBox.idTestBox).toHtml();
557 sHtml += u'</td>';
558 return sHtml;
559
560 def generateReportBody(self):
561 self._sTitle = 'Test Box Failures';
562 oSet = self._oModel.getTestBoxFailures();
563 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
564
565 sHtml = self._generateTableForSet(oSet, 'Test Boxes', aidSortedRaw, iSortColumn);
566 sHtml += self._generateTransitionList(oSet);
567 sHtml += self._generateGraph(oSet, 'testbox-graph', aidSortedRaw);
568 return sHtml;
569
570
571class WuiReportSummary(WuiReportBase):
572 """
573 Summary report.
574 """
575
576 def generateReportBody(self):
577 self._sTitle = 'Summary';
578 sHtml = '<p>This will display several reports and listings useful to get an overview of %s (id=%s).</p>' \
579 % (self._oModel.sSubject, self._oModel.aidSubjects,);
580
581 aoReports = [];
582
583 aoReports.append(WuiReportSuccessRate( self._oModel, self._dParams, fSubReport = True,
584 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
585 aoReports.append(WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True,
586 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
587 if self._oModel.sSubject == ReportModelBase.ksSubTestCase:
588 aoReports.append(WuiReportTestCaseArgsFailures(self._oModel, self._dParams, fSubReport = True,
589 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
590 aoReports.append(WuiReportTestBoxFailures( self._oModel, self._dParams, fSubReport = True,
591 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
592 aoReports.append(WuiReportFailureReasons( self._oModel, self._dParams, fSubReport = True,
593 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
594
595 for oReport in aoReports:
596 (sTitle, sContent) = oReport.show();
597 sHtml += '<br>'; # drop this layout hack
598 sHtml += '<div>';
599 sHtml += '<h3>%s</h3>\n' % (webutils.escapeElem(sTitle),);
600 sHtml += sContent;
601 sHtml += '</div>';
602
603 return sHtml;
604
Note: See TracBrowser for help on using the repository browser.

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