VirtualBox

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

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

testmanager: Added report on faillure reasons, listing first and last build with each.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuireport.py 61254 2016-05-28 01:38:58Z 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: 61254 $"
30
31
32# Validation Kit imports.
33from common import webutils;
34from testmanager.webui.wuicontentbase import WuiContentBase, WuiSvnLinkWithTooltip;
35from testmanager.webui.wuihlpgraph import WuiHlpGraphDataTable, WuiHlpBarGraph;
36from testmanager.core.report import ReportModelBase;
37
38
39class WuiReportBase(WuiContentBase):
40 """
41 Base class for the reports.
42 """
43
44 def __init__(self, oModel, dParams, fSubReport = False, fnDPrint = None, oDisp = None):
45 WuiContentBase.__init__(self, fnDPrint = fnDPrint, oDisp = oDisp);
46 self._oModel = oModel;
47 self._dParams = dParams;
48 self._fSubReport = fSubReport;
49 self._sTitle = None;
50
51 def generateNavigator(self, sWhere):
52 """
53 Generates the navigator (manipulate _dParams).
54 Returns HTML.
55 """
56 assert sWhere == 'top' or sWhere == 'bottom';
57
58 return '';
59
60 def generateReportBody(self):
61 """
62 This is overridden by the child class to generate the report.
63 Returns HTML.
64 """
65 return '<h3>Must override generateReportBody!</h3>';
66
67 def show(self):
68 """
69 Generate the report.
70 Returns (sTitle, HTML).
71 """
72
73 sTitle = self._sTitle if self._sTitle is not None else type(self).__name__;
74 sReport = self.generateReportBody();
75 if not self._fSubReport:
76 sReport = self.generateNavigator('top') + sReport + self.generateNavigator('bottom');
77 sTitle = self._oModel.sSubject + ' - ' + sTitle; ## @todo add subject to title in a proper way!
78
79 return (sTitle, sReport);
80
81
82class WuiReportSuccessRate(WuiReportBase):
83 """
84 Generates a report displaying the success rate over time.
85 """
86
87 def generateReportBody(self):
88 self._sTitle = 'Success rate';
89
90 adPeriods = self._oModel.getSuccessRates();
91
92 sReport = '';
93
94 oTable = WuiHlpGraphDataTable('Period', [ 'Succeeded', 'Skipped', 'Failed' ]);
95
96 #for i in range(len(adPeriods) - 1, -1, -1):
97 for i, dStatuses in enumerate(adPeriods):
98 cSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] + dStatuses[ReportModelBase.ksTestStatus_Skipped];
99 cTotal = cSuccess + dStatuses[ReportModelBase.ksTestStatus_Failure];
100 sPeriod = self._oModel.getPeriodDesc(i);
101 if cTotal > 0:
102 iPctSuccess = dStatuses[ReportModelBase.ksTestStatus_Success] * 100 / cTotal;
103 iPctSkipped = dStatuses[ReportModelBase.ksTestStatus_Skipped] * 100 / cTotal;
104 iPctFailure = dStatuses[ReportModelBase.ksTestStatus_Failure] * 100 / cTotal;
105 oTable.addRow(sPeriod, [ iPctSuccess, iPctSkipped, iPctFailure ],
106 [ '%s%% (%d)' % (iPctSuccess, dStatuses[ReportModelBase.ksTestStatus_Success]),
107 '%s%% (%d)' % (iPctSkipped, dStatuses[ReportModelBase.ksTestStatus_Skipped]),
108 '%s%% (%d)' % (iPctFailure, dStatuses[ReportModelBase.ksTestStatus_Failure]), ]);
109 else:
110 oTable.addRow(sPeriod, [ 0, 0, 0 ], [ '0%', '0%', '0%' ]);
111
112 cTotalNow = adPeriods[0][ReportModelBase.ksTestStatus_Success];
113 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Skipped];
114 cSuccessNow = cTotalNow;
115 cTotalNow += adPeriods[0][ReportModelBase.ksTestStatus_Failure];
116 sReport += '<p>Current success rate: ';
117 if cTotalNow > 0:
118 sReport += '%s%% (thereof %s%% skipped)</p>\n' \
119 % ( cSuccessNow * 100 / cTotalNow, adPeriods[0][ReportModelBase.ksTestStatus_Skipped] * 100 / cTotalNow);
120 else:
121 sReport += 'N/A</p>\n'
122
123 oGraph = WuiHlpBarGraph('success-rate', oTable, self._oDisp);
124 oGraph.setRangeMax(100);
125 sReport += oGraph.renderGraph();
126
127 return sReport;
128
129
130class WuiReportFailureReasons(WuiReportBase):
131 """
132 Generates a report displaying the failure reasons over time.
133 """
134
135 def _formatEdgeOccurence(self, oTransient):
136 """
137 Helper for formatting the transients.
138 oTransient is of type ReportFailureReasonTransient.
139 """
140 sHtml = u'<li>';
141 if oTransient.fEnter: sHtml += 'Since ';
142 else: sHtml += 'Till ';
143 sHtml += WuiSvnLinkWithTooltip(oTransient.iRevision, oTransient.sRepository, fBracketed = 'False').toHtml();
144 sHtml += u', %s: ' % (self.formatTsShort(oTransient.tsDone),);
145 sHtml += u'%s / %s' % (webutils.escapeElem(oTransient.oReason.oCategory.sShort),
146 webutils.escapeElem(oTransient.oReason.sShort),);
147 sHtml += u'</li>\n';
148
149 return sHtml;
150
151
152 def generateReportBody(self):
153 self._sTitle = 'Failure reasons';
154
155 sHtml = u'';
156
157 #
158 # The array of periods we get have the oldest period first [0].
159 #
160 oSet = self._oModel.getFailureReasons();
161
162 #
163 # List failure reasons starting or stopping to appear within the data set.
164 #
165 dtFirstLast = {};
166 for iPeriod, oPeriod in enumerate(oSet.aoPeriods):
167 for oRow in oPeriod.aoRows:
168 tIt = dtFirstLast.get(oRow.idFailureReason, (iPeriod, iPeriod));
169 #sHtml += u'<!-- %d: %d,%d -- %d -->\n' % (oRow.idFailureReason, tIt[0], tIt[1], iPeriod);
170 dtFirstLast[oRow.idFailureReason] = (tIt[0], iPeriod);
171
172 sHtml += '<!-- \n';
173 for iPeriod, oPeriod in enumerate(oSet.aoPeriods):
174 sHtml += ' iPeriod=%d tsStart=%s tsEnd=%s\n' % (iPeriod, oPeriod.tsStart, oPeriod.tsEnd,);
175 sHtml += ' tsMin=%s tsMax=%s\n' % (oPeriod.tsMin, oPeriod.tsMax,);
176 sHtml += ' %d / %s\n' % (oPeriod.iPeriod, oPeriod.sDesc,)
177 sHtml += '-->\n';
178
179 sHtml += u'<h4>Changes:</h4>\n' \
180 u'<ul>\n';
181 if len(oSet.aoEnterInfo) == 0 and len(oSet.aoLeaveInfo) == 0:
182 sHtml += u'<li> No changes</li>\n';
183 else:
184 for oTransient in oSet.aoEnterInfo:
185 sHtml += self._formatEdgeOccurence(oTransient);
186 for oTransient in oSet.aoLeaveInfo:
187 sHtml += self._formatEdgeOccurence(oTransient);
188 sHtml += u'</ul>\n';
189
190 #
191 # Graph.
192 #
193 if True: # pylint: disable=W0125
194 aidSorted = sorted(oSet.dReasons, key = lambda idReason: oSet.dTotals[idReason], reverse = True);
195 else:
196 aidSorted = sorted(oSet.dReasons,
197 key = lambda idReason: '%s / %s' % (oSet.dReasons[idReason].oCategory.sShort,
198 oSet.dReasons[idReason].sShort,));
199
200 asNames = [];
201 for idReason in aidSorted:
202 oReason = oSet.dReasons[idReason];
203 asNames.append('%s / %s' % (oReason.oCategory.sShort, oReason.sShort,) )
204 oTable = WuiHlpGraphDataTable('Period', asNames);
205
206 for iPeriod, oPeriod in enumerate(reversed(oSet.aoPeriods)):
207 aiValues = [];
208 for idReason in aidSorted:
209 oRow = oPeriod.dById.get(idReason, None);
210 iValue = oRow.cHits if oRow is not None else 0;
211 aiValues.append(iValue);
212 oTable.addRow(oPeriod.sDesc, aiValues);
213
214 oGraph = WuiHlpBarGraph('failure-reason', oTable, self._oDisp);
215 oGraph.setRangeMax(max(oSet.cMaxRowHits + 1, 3));
216 sHtml += oGraph.renderGraph();
217
218 #
219 # Table form necessary?
220 #
221 #sHtml += u'<p>TODO: Show graph content in table form.</p>';
222
223 return sHtml;
224
225
226class WuiReportSummary(WuiReportBase):
227 """
228 Summary report.
229 """
230
231 def generateReportBody(self):
232 self._sTitle = 'Summary';
233 sHtml = '<p>This will display several reports and listings useful to get an overview of %s (id=%s).</p>' \
234 % (self._oModel.sSubject, self._oModel.aidSubjects,);
235
236 oSuccessRate = WuiReportSuccessRate(self._oModel, self._dParams, fSubReport = True,
237 fnDPrint = self._fnDPrint, oDisp = self._oDisp);
238
239
240
241 oFailureReasons = WuiReportFailureReasons(self._oModel, self._dParams, fSubReport = True,
242 fnDPrint = self._fnDPrint, oDisp = self._oDisp);
243 for oReport in [oSuccessRate, oFailureReasons, ]:
244 (sTitle, sContent) = oReport.show();
245 sHtml += '<br>'; # drop this layout hack
246 sHtml += '<div>';
247 sHtml += '<h3>%s</h3>\n' % (webutils.escapeElem(sTitle),);
248 sHtml += sContent;
249 sHtml += '</div>';
250
251 return sHtml;
252
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