VirtualBox

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

Last change on this file since 65445 was 65443, checked in by vboxsync, 8 years ago

pylint

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuireport.py 65443 2017-01-25 14:26:35Z vboxsync $
3
4"""
5Test Manager WUI - Reports.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2016 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: 65443 $"
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, aiSortColumns = None, 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 self._aiSortColumns = aiSortColumns;
76
77 # Additional URL parameters for reports
78 self._dExtraParams = {};
79 dCurParams = None if oDisp is None else oDisp.getParameters();
80 if dCurParams is not None:
81 from testmanager.webui.wuimain import WuiMain;
82 for sExtraParam in [ WuiMain.ksParamReportPeriods, WuiMain.ksParamReportPeriodInHours,
83 WuiMain.ksParamEffectiveDate, ]:
84 if sExtraParam in dCurParams:
85 self._dExtraParams[sExtraParam] = dCurParams[sExtraParam];
86
87
88 def generateNavigator(self, sWhere):
89 """
90 Generates the navigator (manipulate _dParams).
91 Returns HTML.
92 """
93 assert sWhere == 'top' or sWhere == 'bottom';
94
95 return '';
96
97 def generateReportBody(self):
98 """
99 This is overridden by the child class to generate the report.
100 Returns HTML.
101 """
102 return '<h3>Must override generateReportBody!</h3>';
103
104 def show(self):
105 """
106 Generate the report.
107 Returns (sTitle, HTML).
108 """
109
110 sTitle = self._sTitle if self._sTitle is not None else type(self).__name__;
111 sReport = self.generateReportBody();
112 if not self._fSubReport:
113 sReport = self.generateNavigator('top') + sReport + self.generateNavigator('bottom');
114 sTitle = self._oModel.sSubject + ' - ' + sTitle; ## @todo add subject to title in a proper way!
115
116 sReport += '\n\n<!-- HEYYOU: sSubject=%s aidSubjects=%s -->\n\n' % (self._oModel.sSubject, self._oModel.aidSubjects);
117 return (sTitle, sReport);
118
119
120class WuiReportSuccessRate(WuiReportBase):
121 """
122 Generates a report displaying the success rate over time.
123 """
124
125 def generateReportBody(self):
126 self._sTitle = 'Success rate';
127
128 adPeriods = self._oModel.getSuccessRates();
129
130 sReport = '';
131
132 oTable = WuiHlpGraphDataTable('Period', [ 'Succeeded', 'Skipped', 'Failed' ]);
133
134 #for i in range(len(adPeriods) - 1, -1, -1):
135 for i, dStatuses in enumerate(adPeriods):
136 cSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] + dStatuses[ReportModelBase.ksTestStatus_Skipped];
137 cTotal = cSuccess + dStatuses[ReportModelBase.ksTestStatus_Failure];
138 sPeriod = self._oModel.getPeriodDesc(i);
139 if cTotal > 0:
140 iPctSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] * 100 / cTotal;
141 iPctSkipped = dStatuses[ReportModelBase.ksTestStatus_Skipped] * 100 / cTotal;
142 iPctFailure = dStatuses[ReportModelBase.ksTestStatus_Failure] * 100 / cTotal;
143 oTable.addRow(sPeriod, [ iPctSuccess, iPctSkipped, iPctFailure ],
144 [ '%s%% (%d)' % (iPctSuccess, dStatuses[ReportModelBase.ksTestStatus_Success]),
145 '%s%% (%d)' % (iPctSkipped, dStatuses[ReportModelBase.ksTestStatus_Skipped]),
146 '%s%% (%d)' % (iPctFailure, dStatuses[ReportModelBase.ksTestStatus_Failure]), ]);
147 else:
148 oTable.addRow(sPeriod, [ 0, 0, 0 ], [ '0%', '0%', '0%' ]);
149
150 cTotalNow = adPeriods[0][ReportModelBase.ksTestStatus_Success];
151 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Skipped];
152 cSuccessNow = cTotalNow;
153 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Failure];
154 sReport += '<p>Current success rate: ';
155 if cTotalNow > 0:
156 sReport += '%s%% (thereof %s%% skipped)</p>\n' \
157 % ( cSuccessNow * 100 / cTotalNow, adPeriods[0][ReportModelBase.ksTestStatus_Skipped] * 100 / cTotalNow);
158 else:
159 sReport += 'N/A</p>\n'
160
161 oGraph = WuiHlpBarGraph('success-rate', oTable, self._oDisp);
162 oGraph.setRangeMax(100);
163 sReport += oGraph.renderGraph();
164
165 return sReport;
166
167
168class WuiReportFailuresBase(WuiReportBase):
169 """
170 Common parent of WuiReportFailureReasons and WuiReportTestCaseFailures.
171 """
172
173 def _splitSeriesIntoMultipleGraphs(self, aidSorted, cMaxSeriesPerGraph = 8):
174 """
175 Splits the ID array into one or more arrays, making sure we don't
176 have too many series per graph.
177 Returns array of ID arrays.
178 """
179 if len(aidSorted) <= cMaxSeriesPerGraph + 2:
180 return [aidSorted,];
181 cGraphs = len(aidSorted) / cMaxSeriesPerGraph + (len(aidSorted) % cMaxSeriesPerGraph != 0);
182 cPerGraph = len(aidSorted) / cGraphs + (len(aidSorted) % cGraphs != 0);
183
184 aaoRet = [];
185 cLeft = len(aidSorted);
186 iSrc = 0;
187 while cLeft > 0:
188 cThis = cPerGraph;
189 if cLeft <= cPerGraph + 2:
190 cThis = cLeft;
191 elif cLeft <= cPerGraph * 2 + 4:
192 cThis = cLeft / 2;
193 aaoRet.append(aidSorted[iSrc : iSrc + cThis]);
194 iSrc += cThis;
195 cLeft -= cThis;
196 return aaoRet;
197
198 def _formatEdgeOccurenceSubject(self, oTransient):
199 """
200 Worker for _formatEdgeOccurence that child classes overrides to format
201 their type of subject data in the best possible way.
202 """
203 _ = oTransient;
204 assert False;
205 return '';
206
207 def _formatEdgeOccurence(self, oTransient):
208 """
209 Helper for formatting the transients.
210 oTransient is of type ReportFailureReasonTransient or ReportTestCaseFailureTransient.
211 """
212 sHtml = u'<li>';
213 if oTransient.fEnter: sHtml += 'Since ';
214 else: sHtml += 'Until ';
215 sHtml += WuiSvnLinkWithTooltip(oTransient.iRevision, oTransient.sRepository, fBracketed = 'False').toHtml();
216 sHtml += u', %s: ' % (WuiTestSetLink(oTransient.idTestSet, self.formatTsShort(oTransient.tsDone),
217 fBracketed = False).toHtml(), )
218 sHtml += self._formatEdgeOccurenceSubject(oTransient);
219 sHtml += u'</li>\n';
220 return sHtml;
221
222 def _generateTransitionList(self, oSet):
223 """
224 Generates the enter and leave lists.
225 """
226 # Skip this if we're looking at builds.
227 if self._oModel.sSubject in [self._oModel.ksSubBuild,] and len(self._oModel.aidSubjects) in [1, 2]:
228 return u'';
229
230 sHtml = u'<h4>Movements:</h4>\n' \
231 u'<ul>\n';
232 if len(oSet.aoEnterInfo) == 0 and len(oSet.aoLeaveInfo) == 0:
233 sHtml += u'<li>No changes</li>\n';
234 else:
235 for oTransient in oSet.aoEnterInfo:
236 sHtml += self._formatEdgeOccurence(oTransient);
237 for oTransient in oSet.aoLeaveInfo:
238 sHtml += self._formatEdgeOccurence(oTransient);
239 sHtml += u'</ul>\n';
240
241 return sHtml;
242
243
244 def _formatSeriesNameColumnHeadersForTable(self):
245 """ Formats the series name column for the HTML table. """
246 return '<th>Subject Name</th>';
247
248 def _formatSeriesNameForTable(self, oSet, idKey):
249 """ Formats the series name for the HTML table. """
250 _ = oSet;
251 return '<td>%d</td>' % (idKey,);
252
253 def _formatRowValueForTable(self, oRow, oPeriod, cColsPerSeries):
254 """ Formats a row value for the HTML table. """
255 _ = oPeriod;
256 if oRow is None:
257 return u'<td colspan="%d"> </td>' % (cColsPerSeries,);
258 if cColsPerSeries == 2:
259 return u'<td align="right">%u%%</td><td align="center">%u / %u</td>' \
260 % (oRow.cHits * 100 / oRow.cTotal, oRow.cHits, oRow.cTotal);
261 return u'<td align="center">%u</td>' % (oRow.cHits,);
262
263 def _formatSeriesTotalForTable(self, oSet, idKey, cColsPerSeries):
264 """ Formats the totals cell for a data series in the HTML table. """
265 dcTotalPerId = getattr(oSet, 'dcTotalPerId', None);
266 if cColsPerSeries == 2:
267 return u'<td align="right">%u%%</td><td align="center">%u/%u</td>' \
268 % (oSet.dcHitsPerId[idKey] * 100 / dcTotalPerId[idKey], oSet.dcHitsPerId[idKey], dcTotalPerId[idKey]);
269 return u'<td align="center">%u</td>' % (oSet.dcHitsPerId[idKey],);
270
271 def _generateTableForSet(self, oSet, aidSorted = None, iSortColumn = 0,
272 fWithTotals = True, cColsPerSeries = None):
273 """
274 Turns the set into a table.
275
276 Returns raw html.
277 """
278 sHtml = u'<table class="tmtbl-report-set" width="100%%">\n';
279 if cColsPerSeries is None:
280 cColsPerSeries = 2 if hasattr(oSet, 'dcTotalPerId') else 1;
281
282 # Header row.
283 sHtml += u' <tr><thead><th>#</th>';
284 sHtml += self._formatSeriesNameColumnHeadersForTable();
285 for iPeriod, oPeriod in enumerate(reversed(oSet.aoPeriods)):
286 sHtml += u'<th colspan="%d"><a href="javascript:ahrefActionSortByColumns(\'%s\',[%s]);">%s</a>%s</th>' \
287 % ( cColsPerSeries, self._oDisp.ksParamSortColumns, iPeriod, webutils.escapeElem(oPeriod.sDesc),
288 '&#x25bc;' if iPeriod == iSortColumn else '');
289 if fWithTotals:
290 sHtml += u'<th colspan="%d"><a href="javascript:ahrefActionSortByColumns(\'%s\',[%s]);">Total</a>%s</th>' \
291 % ( cColsPerSeries, self._oDisp.ksParamSortColumns, len(oSet.aoPeriods),
292 '&#x25bc;' if iSortColumn == len(oSet.aoPeriods) else '');
293 sHtml += u'</thead></td>\n';
294
295 # Each data series.
296 if aidSorted is None:
297 aidSorted = oSet.dSubjects.keys();
298 sHtml += u' <tbody>\n';
299 for iRow, idKey in enumerate(aidSorted):
300 sHtml += u' <tr class="%s">' % ('tmodd' if iRow & 1 else 'tmeven',);
301 sHtml += u'<td align="left">#%u</td>' % (iRow + 1,);
302 sHtml += self._formatSeriesNameForTable(oSet, idKey);
303 for oPeriod in reversed(oSet.aoPeriods):
304 oRow = oPeriod.dRowsById.get(idKey, None);
305 sHtml += self._formatRowValueForTable(oRow, oPeriod, cColsPerSeries);
306 if fWithTotals:
307 sHtml += self._formatSeriesTotalForTable(oSet, idKey, cColsPerSeries);
308 sHtml += u' </tr>\n';
309 sHtml += u' </tbody>\n';
310 sHtml += u'</table>\n';
311 return sHtml;
312
313
314class WuiReportFailuresWithTotalBase(WuiReportFailuresBase):
315 """
316 For ReportPeriodSetWithTotalBase.
317 """
318
319 def _formatSeriedNameForGraph(self, oSubject):
320 """
321 Format the subject name for the graph.
322 """
323 return str(oSubject);
324
325 def _getSortedIds(self, oSet):
326 """
327 Get default sorted subject IDs and which column.
328 """
329
330 # Figure the sorting column.
331 if self._aiSortColumns is not None \
332 and len(self._aiSortColumns) > 0 \
333 and abs(self._aiSortColumns[0]) <= len(oSet.aoPeriods):
334 iSortColumn = abs(self._aiSortColumns[0]);
335 fByTotal = iSortColumn >= len(oSet.aoPeriods); # pylint: disable=unused-variable
336 elif oSet.cMaxTotal < 10:
337 iSortColumn = len(oSet.aoPeriods);
338 else:
339 iSortColumn = 0;
340
341 if iSortColumn >= len(oSet.aoPeriods):
342 # Sort the total.
343 aidSortedRaw = sorted(oSet.dSubjects,
344 key = lambda idKey: oSet.dcHitsPerId[idKey] * 10000 / oSet.dcTotalPerId[idKey],
345 reverse = True);
346 else:
347 # Sort by NOW column.
348 dTmp = {};
349 for idKey in oSet.dSubjects:
350 oRow = oSet.aoPeriods[-1 - iSortColumn].dRowsById.get(idKey, None);
351 if oRow is None: dTmp[idKey] = 0;
352 else: dTmp[idKey] = oRow.cHits * 10000 / max(1, oRow.cTotal);
353 aidSortedRaw = sorted(dTmp, key = lambda idKey: dTmp[idKey], reverse = True);
354 return (aidSortedRaw, iSortColumn);
355
356 def _generateGraph(self, oSet, sIdBase, aidSortedRaw):
357 """
358 Generates graph.
359 """
360 sHtml = u'';
361 fGenerateGraph = len(aidSortedRaw) <= 6 and len(aidSortedRaw) > 0; ## Make this configurable.
362 if fGenerateGraph:
363 # Figure the graph width for all of them.
364 uPctMax = max(oSet.uMaxPct, oSet.cMaxHits * 100 / oSet.cMaxTotal);
365 uPctMax = max(uPctMax + 2, 10);
366
367 for _, aidSorted in enumerate(self._splitSeriesIntoMultipleGraphs(aidSortedRaw, 8)):
368 asNames = [];
369 for idKey in aidSorted:
370 oSubject = oSet.dSubjects[idKey];
371 asNames.append(self._formatSeriedNameForGraph(oSubject));
372
373 oTable = WuiHlpGraphDataTable('Period', asNames);
374
375 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
376 aiValues = [];
377 asValues = [];
378
379 for idKey in aidSorted:
380 oRow = oPeriod.dRowsById.get(idKey, None);
381 if oRow is not None:
382 uPct = oRow.cHits * 100 / oRow.cTotal;
383 aiValues.append(uPct);
384 asValues.append('%u%% (%u/%u)' % (uPct, oRow.cHits, oRow.cTotal));
385 else:
386 aiValues.append(0);
387 asValues.append('0');
388
389 oTable.addRow(oPeriod.sDesc, aiValues, asValues);
390
391 if True: # pylint: disable=W0125
392 aiValues = [];
393 asValues = [];
394 for idKey in aidSorted:
395 uPct = oSet.dcHitsPerId[idKey] * 100 / oSet.dcTotalPerId[idKey];
396 aiValues.append(uPct);
397 asValues.append('%u%% (%u/%u)' % (uPct, oSet.dcHitsPerId[idKey], oSet.dcTotalPerId[idKey]));
398 oTable.addRow('Totals', aiValues, asValues);
399
400 oGraph = WuiHlpBarGraph(sIdBase, oTable, self._oDisp);
401 oGraph.setRangeMax(uPctMax);
402 sHtml += '<br>\n';
403 sHtml += oGraph.renderGraph();
404 return sHtml;
405
406
407
408class WuiReportFailureReasons(WuiReportFailuresBase):
409 """
410 Generates a report displaying the failure reasons over time.
411 """
412
413 def _formatEdgeOccurenceSubject(self, oTransient):
414 return u'%s / %s' % ( webutils.escapeElem(oTransient.oReason.oCategory.sShort),
415 webutils.escapeElem(oTransient.oReason.sShort),);
416
417 def _formatSeriesNameColumnHeadersForTable(self):
418 return '<th>Failure Reason</th>';
419
420 def _formatSeriesNameForTable(self, oSet, idKey):
421 oReason = oSet.dSubjects[idKey];
422 sHtml = u'<td>';
423 sHtml += u'%s / %s' % ( webutils.escapeElem(oReason.oCategory.sShort), webutils.escapeElem(oReason.sShort),);
424 sHtml += u'</td>';
425 return sHtml;
426
427
428 def generateReportBody(self):
429 self._sTitle = 'Failure reasons';
430
431 #
432 # Get the data and sort the data series in descending order of badness.
433 #
434 oSet = self._oModel.getFailureReasons();
435 aidSortedRaw = sorted(oSet.dSubjects, key = lambda idReason: oSet.dcHitsPerId[idReason], reverse = True);
436
437 #
438 # Generate table and transition list. These are the most useful ones with the current graph machinery.
439 #
440 sHtml = self._generateTableForSet(oSet, aidSortedRaw, len(oSet.aoPeriods));
441 sHtml += self._generateTransitionList(oSet);
442
443 #
444 # Check if most of the stuff is without any assign reason, if so, skip
445 # that part of the graph so it doesn't offset the interesting bits.
446 #
447 fIncludeWithoutReason = True;
448 for oPeriod in reversed(oSet.aoPeriods):
449 if oPeriod.cWithoutReason > oSet.cMaxHits * 4:
450 fIncludeWithoutReason = False;
451 sHtml += '<p>Warning: Many failures without assigned reason!</p>\n';
452 break;
453
454 #
455 # Generate the graph.
456 #
457 fGenerateGraph = len(aidSortedRaw) <= 9 and len(aidSortedRaw) > 0; ## Make this configurable.
458 if fGenerateGraph:
459 aidSorted = aidSortedRaw;
460
461 asNames = [];
462 for idReason in aidSorted:
463 oReason = oSet.dSubjects[idReason];
464 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
465 if fIncludeWithoutReason:
466 asNames.append('No reason');
467
468 oTable = WuiHlpGraphDataTable('Period', asNames);
469
470 cMax = oSet.cMaxHits;
471 for _, oPeriod in enumerate(reversed(oSet.aoPeriods)):
472 aiValues = [];
473
474 for idReason in aidSorted:
475 oRow = oPeriod.dRowsById.get(idReason, None);
476 iValue = oRow.cHits if oRow is not None else 0;
477 aiValues.append(iValue);
478
479 if fIncludeWithoutReason:
480 aiValues.append(oPeriod.cWithoutReason);
481 if oPeriod.cWithoutReason > cMax:
482 cMax = oPeriod.cWithoutReason;
483
484 oTable.addRow(oPeriod.sDesc, aiValues);
485
486 oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
487 oGraph.setRangeMax(max(cMax + 1, 3));
488 sHtml += oGraph.renderGraph();
489 return sHtml;
490
491
492class WuiReportTestCaseFailures(WuiReportFailuresWithTotalBase):
493 """
494 Generates a report displaying the failure reasons over time.
495 """
496
497 def _formatEdgeOccurenceSubject(self, oTransient):
498 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
499 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
500 return sHtml;
501
502 def _formatSeriesNameColumnHeadersForTable(self):
503 return '<th>Test Case</th>';
504
505 def _formatSeriesNameForTable(self, oSet, idKey):
506 oTestCase = oSet.dSubjects[idKey];
507 sHtml = u'<td>';
508 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCase.idTestCase, sName = oTestCase.sName,
509 dExtraParams = self._dExtraParams).toHtml();
510 sHtml += u' ';
511 sHtml += WuiTestCaseDetailsLink(oTestCase.idTestCase).toHtml();
512 sHtml += u'</td>';
513 return sHtml;
514
515 def _formatSeriedNameForGraph(self, oSubject):
516 return oSubject.sName;
517
518 def generateReportBody(self):
519 self._sTitle = 'Test Case Failures';
520 oSet = self._oModel.getTestCaseFailures();
521 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
522
523 sHtml = self._generateTableForSet(oSet, aidSortedRaw, iSortColumn);
524 sHtml += self._generateTransitionList(oSet);
525 sHtml += self._generateGraph(oSet, 'testcase-graph', aidSortedRaw);
526 return sHtml;
527
528
529class WuiReportTestCaseArgsFailures(WuiReportFailuresWithTotalBase):
530 """
531 Generates a report displaying the failure reasons over time.
532 """
533
534 @staticmethod
535 def _formatName(oTestCaseArgs):
536 """ Internal helper for formatting the testcase name. """
537 if oTestCaseArgs.sSubName is not None and len(oTestCaseArgs.sSubName) > 0:
538 sName = u'%s / %s' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.sSubName, );
539 else:
540 sName = u'%s / #%u' % ( oTestCaseArgs.oTestCase.sName, oTestCaseArgs.idTestCaseArgs, );
541 return sName;
542
543 def _formatEdgeOccurenceSubject(self, oTransient):
544 sHtml = u'%s ' % ( webutils.escapeElem(self._formatName(oTransient.oSubject)),);
545 sHtml += WuiTestCaseDetailsLink(oTransient.oSubject.idTestCase, fBracketed = False).toHtml();
546 return sHtml;
547
548 def _formatSeriesNameColumnHeadersForTable(self):
549 return '<th>Test Case / Variation</th>';
550
551 def _formatSeriesNameForTable(self, oSet, idKey):
552 oTestCaseArgs = oSet.dSubjects[idKey];
553 sHtml = u'<td>';
554 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestCaseArgs, oTestCaseArgs.idTestCaseArgs,
555 sName = self._formatName(oTestCaseArgs), dExtraParams = self._dExtraParams).toHtml();
556 sHtml += u' ';
557 sHtml += WuiTestCaseDetailsLink(oTestCaseArgs.idTestCase).toHtml();
558 sHtml += u'</td>';
559 return sHtml;
560
561 def _formatSeriedNameForGraph(self, oSubject):
562 return self._formatName(oSubject);
563
564 def generateReportBody(self):
565 self._sTitle = 'Test Case Variation Failures';
566 oSet = self._oModel.getTestCaseVariationFailures();
567 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
568
569 sHtml = self._generateTableForSet(oSet, aidSortedRaw, iSortColumn);
570 sHtml += self._generateTransitionList(oSet);
571 sHtml += self._generateGraph(oSet, 'testcasearg-graph', aidSortedRaw);
572 return sHtml;
573
574
575
576class WuiReportTestBoxFailures(WuiReportFailuresWithTotalBase):
577 """
578 Generates a report displaying the failure reasons over time.
579 """
580
581 def _formatEdgeOccurenceSubject(self, oTransient):
582 sHtml = u'%s ' % ( webutils.escapeElem(oTransient.oSubject.sName),);
583 sHtml += WuiTestBoxDetailsLink(oTransient.oSubject.idTestBox, fBracketed = False).toHtml();
584 return sHtml;
585
586 def _formatSeriesNameColumnHeadersForTable(self):
587 return '<th colspan="5">Test Box</th>';
588
589 def _formatSeriesNameForTable(self, oSet, idKey):
590 oTestBox = oSet.dSubjects[idKey];
591 sHtml = u'<td>';
592 sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestBox.idTestBox, sName = oTestBox.sName,
593 dExtraParams = self._dExtraParams).toHtml();
594 sHtml += u' ';
595 sHtml += WuiTestBoxDetailsLink(oTestBox.idTestBox).toHtml();
596 sHtml += u'</td>';
597 sOsAndVer = '%s %s' % (oTestBox.sOs, oTestBox.sOsVersion.strip(),);
598 if len(sOsAndVer) < 22:
599 sHtml += u'<td>%s</td>' % (webutils.escapeElem(sOsAndVer),);
600 else: # wonder if td.title works..
601 sHtml += u'<td title="%s" width="1%%" style="white-space:nowrap;">%s...</td>' \
602 % (webutils.escapeAttr(sOsAndVer), webutils.escapeElem(sOsAndVer[:20]));
603 sHtml += u'<td>%s</td>' % (webutils.escapeElem(oTestBox.getArchBitString()),);
604 sHtml += u'<td>%s</td>' % (webutils.escapeElem(oTestBox.getPrettyCpuVendor()),);
605 sHtml += u'<td>%s' % (oTestBox.getPrettyCpuVersion(),);
606 if oTestBox.fCpuNestedPaging: sHtml += u', np';
607 elif oTestBox.fCpuHwVirt: sHtml += u', hw';
608 else: sHtml += u', raw';
609 if oTestBox.fCpu64BitGuest: sHtml += u', 64';
610 sHtml += u'</td>';
611 return sHtml;
612
613 def _formatSeriedNameForGraph(self, oSubject):
614 return oSubject.sName;
615
616 def generateReportBody(self):
617 self._sTitle = 'Test Box Failures';
618 oSet = self._oModel.getTestBoxFailures();
619 (aidSortedRaw, iSortColumn) = self._getSortedIds(oSet);
620
621 sHtml = self._generateTableForSet(oSet, aidSortedRaw, iSortColumn);
622 sHtml += self._generateTransitionList(oSet);
623 sHtml += self._generateGraph(oSet, 'testbox-graph', aidSortedRaw);
624 return sHtml;
625
626
627class WuiReportSummary(WuiReportBase):
628 """
629 Summary report.
630 """
631
632 def generateReportBody(self):
633 self._sTitle = 'Summary';
634 sHtml = '<p>This will display several reports and listings useful to get an overview of %s (id=%s).</p>' \
635 % (self._oModel.sSubject, self._oModel.aidSubjects,);
636
637 aoReports = [];
638
639 aoReports.append(WuiReportSuccessRate( self._oModel, self._dParams, fSubReport = True,
640 aiSortColumns = self._aiSortColumns,
641 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
642 aoReports.append(WuiReportTestCaseFailures(self._oModel, self._dParams, fSubReport = True,
643 aiSortColumns = self._aiSortColumns,
644 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
645 if self._oModel.sSubject == ReportModelBase.ksSubTestCase:
646 aoReports.append(WuiReportTestCaseArgsFailures(self._oModel, self._dParams, fSubReport = True,
647 aiSortColumns = self._aiSortColumns,
648 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
649 aoReports.append(WuiReportTestBoxFailures( self._oModel, self._dParams, fSubReport = True,
650 aiSortColumns = self._aiSortColumns,
651 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
652 aoReports.append(WuiReportFailureReasons( self._oModel, self._dParams, fSubReport = True,
653 aiSortColumns = self._aiSortColumns,
654 fnDPrint = self._fnDPrint, oDisp = self._oDisp));
655
656 for oReport in aoReports:
657 (sTitle, sContent) = oReport.show();
658 sHtml += '<br>'; # drop this layout hack
659 sHtml += '<div>';
660 sHtml += '<h3>%s</h3>\n' % (webutils.escapeElem(sTitle),);
661 sHtml += sContent;
662 sHtml += '</div>';
663
664 return sHtml;
665
Note: See TracBrowser for help on using the repository browser.

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