VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuimain.py@ 61220

最後變更 在這個檔案從61220是 61219,由 vboxsync 提交於 9 年 前

testmanager: give reason to failures (quick hack, can do prettier later).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 54.3 KB
 
1# -*- coding: utf-8 -*-
2# $Id: wuimain.py 61219 2016-05-26 20:15:02Z vboxsync $
3
4"""
5Test Manager Core - WUI - The Main page.
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.alldomusa.eu.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: 61219 $"
30
31# Standard Python imports.
32
33# Validation Kit imports.
34from testmanager import config;
35from testmanager.webui.wuibase import WuiDispatcherBase, WuiException;
36from testmanager.webui.wuicontentbase import WuiTmLink;
37from testmanager.core.report import ReportLazyModel, ReportGraphModel, ReportModelBase;
38from testmanager.core.testresults import TestResultLogic, TestResultFileDataEx;
39from testmanager.core.base import TMExceptionBase, TMTooManyRows;
40from testmanager.core.testset import TestSetData, TestSetLogic;
41from testmanager.core.build import BuildDataEx;
42from testmanager.core.testbox import TestBoxData
43from testmanager.core.testgroup import TestGroupData;
44from testmanager.core.testcase import TestCaseDataEx
45from testmanager.core.testcaseargs import TestCaseArgsDataEx
46from testmanager.core.vcsrevisions import VcsRevisionLogic;
47from common import webutils, utils;
48
49
50class WuiMain(WuiDispatcherBase):
51 """
52 WUI Main page.
53
54 Note! All cylic dependency avoiance stuff goes here in the dispatcher code,
55 not in the action specific code. This keeps the uglyness in one place
56 and reduces load time dependencies in the more critical code path.
57 """
58
59 ## The name of the script.
60 ksScriptName = 'index.py'
61
62 ## @name Actions
63 ## @{
64 ksActionResultsUnGrouped = 'ResultsUnGrouped'
65 ksActionResultsGroupedBySchedGroup = 'ResultsGroupedBySchedGroup'
66 ksActionResultsGroupedByTestGroup = 'ResultsGroupedByTestGroup'
67 ksActionResultsGroupedByBuildRev = 'ResultsGroupedByBuildRev'
68 ksActionResultsGroupedByTestBox = 'ResultsGroupedByTestBox'
69 ksActionResultsGroupedByTestCase = 'ResultsGroupedByTestCase'
70 ksActionTestResultDetails = 'TestResultDetails'
71 ksActionTestResultFailureDetails = 'TestResultFailureDetails'
72 ksActionTestResultFailureAdd = 'TestResultFailureAdd'
73 ksActionTestResultFailureAddPost = 'TestResultFailureAddPost'
74 ksActionTestResultFailureEdit = 'TestResultFailureEdit'
75 ksActionTestResultFailureEditPost = 'TestResultFailureEditPost'
76 ksActionViewLog = 'ViewLog'
77 ksActionGetFile = 'GetFile'
78 ksActionReportSummary = 'ReportSummary';
79 ksActionReportRate = 'ReportRate';
80 ksActionReportFailureReasons = 'ReportFailureReasons';
81 ksActionGraphWiz = 'GraphWiz';
82 ksActionVcsHistoryTooltip = 'VcsHistoryTooltip';
83 ## @}
84
85 ## @name Standard report parameters
86 ## @{
87 ksParamReportPeriods = 'cPeriods';
88 ksParamReportPeriodInHours = 'cHoursPerPeriod';
89 ksParamReportSubject = 'sSubject';
90 ksParamReportSubjectIds = 'SubjectIds';
91 ## @}
92
93 ## @name Graph Wizard parameters
94 ## Common parameters: ksParamReportPeriods, ksParamReportPeriodInHours, ksParamReportSubjectIds,
95 ## ksParamReportSubject, ksParamEffectivePeriod, and ksParamEffectiveDate.
96 ## @{
97 ksParamGraphWizTestBoxIds = 'aidTestBoxes';
98 ksParamGraphWizBuildCatIds = 'aidBuildCats';
99 ksParamGraphWizTestCaseIds = 'aidTestCases';
100 ksParamGraphWizSepTestVars = 'fSepTestVars';
101 ksParamGraphWizImpl = 'enmImpl';
102 ksParamGraphWizWidth = 'cx';
103 ksParamGraphWizHeight = 'cy';
104 ksParamGraphWizDpi = 'dpi';
105 ksParamGraphWizFontSize = 'cPtFont';
106 ksParamGraphWizErrorBarY = 'fErrorBarY';
107 ksParamGraphWizMaxErrorBarY = 'cMaxErrorBarY';
108 ksParamGraphWizMaxPerGraph = 'cMaxPerGraph';
109 ksParamGraphWizXkcdStyle = 'fXkcdStyle';
110 ksParamGraphWizTabular = 'fTabular';
111 ksParamGraphWizSrcTestSetId = 'idSrcTestSet';
112 ## @}
113
114 ## @name Graph implementations values for ksParamGraphWizImpl.
115 ## @{
116 ksGraphWizImpl_Default = 'default';
117 ksGraphWizImpl_Matplotlib = 'matplotlib';
118 ksGraphWizImpl_Charts = 'charts';
119 kasGraphWizImplValid = [ ksGraphWizImpl_Default, ksGraphWizImpl_Matplotlib, ksGraphWizImpl_Charts];
120 kaasGraphWizImplCombo = [
121 ( ksGraphWizImpl_Default, 'Default' ),
122 ( ksGraphWizImpl_Matplotlib, 'Matplotlib (server)' ),
123 ( ksGraphWizImpl_Charts, 'Google Charts (client)'),
124 ];
125 ## @}
126
127 ## @name Log Viewer parameters.
128 ## @{
129 ksParamLogSetId = 'LogViewer_idTestSet';
130 ksParamLogFileId = 'LogViewer_idFile';
131 ksParamLogChunkSize = 'LogViewer_cbChunk';
132 ksParamLogChunkNo = 'LogViewer_iChunk';
133 ## @}
134
135 ## @name File getter parameters.
136 ## @{
137 ksParamGetFileSetId = 'GetFile_idTestSet';
138 ksParamGetFileId = 'GetFile_idFile';
139 ksParamGetFileDownloadIt = 'GetFile_fDownloadIt';
140 ## @}
141
142 ## @name VCS history parameters.
143 ## @{
144 ksParamVcsHistoryRepository = 'repo';
145 ksParamVcsHistoryRevision = 'rev';
146 ksParamVcsHistoryEntries = 'cEntries';
147 ## @}
148
149 ## @name Test result listing parameters.
150 ## @{
151 ## If this param is specified, then show only results for this member when results grouped by some parameter.
152 ksParamGroupMemberId = 'GroupMemberId'
153 ## Optional parameter for indicating whether to restrict the listing to failures only.
154 ksParamOnlyFailures = 'OnlyFailures'
155 ## Result listing sorting.
156 ksParamTestResultsSortBy = 'enmSortBy'
157 ## @}
158
159 ## Effective time period. one of the first column values in kaoResultPeriods.
160 ksParamEffectivePeriod = 'sEffectivePeriod'
161
162 ## Test result period values.
163 kaoResultPeriods = [
164 ( '1 hour', 'One hour', 1 ),
165 ( '2 hours', 'Two hours', 2 ),
166 ( '3 hours', 'Three hours', 3 ),
167 ( '6 hours', 'Six hours', 6 ),
168 ( '12 hours', '12 hours', 12 ),
169
170 ( '1 day', 'One day', 24 ),
171 ( '2 days', 'Two days', 48 ),
172 ( '3 days', 'Three days', 72 ),
173
174 ( '1 week', 'One week', 168 ),
175 ( '2 weeks', 'Two weeks', 336 ),
176 ( '3 weeks', 'Three weeks', 504 ),
177
178 ( '1 month', 'One month', 31 * 24 ), # The approx hour count varies with the start date.
179 ( '2 months', 'Two month', (31 + 31) * 24 ), # Using maximum values.
180 ( '3 months', 'Three month', (31 + 30 + 31) * 24 ),
181
182 ( '6 months', 'Six month', (31 + 31 + 30 + 31 + 30 + 31) * 24 ),
183
184 ( '1 year', 'One year', 365 * 24 ),
185 ];
186 ## The default test result period.
187 ksResultPeriodDefault = '6 hours';
188
189
190
191 def __init__(self, oSrvGlue):
192 WuiDispatcherBase.__init__(self, oSrvGlue, self.ksScriptName);
193
194 self._sTemplate = 'template.html'
195
196 #
197 # Populate the action dispatcher dictionary.
198 #
199
200 # Use short form to avoid hitting the right margin (130) when using lambda.
201 d = self._dDispatch; # pylint: disable=C0103
202
203 from testmanager.webui.wuitestresult import WuiGroupedResultList;
204 #d[self.ksActionResultsUnGrouped] = lambda: self._actionResultsListing(TestResultLogic, WuiGroupedResultList)
205 d[self.ksActionResultsUnGrouped] = lambda: self._actionGroupedResultsListing(
206 TestResultLogic.ksResultsGroupingTypeNone,
207 TestResultLogic,
208 WuiGroupedResultList)
209
210 d[self.ksActionResultsGroupedByTestGroup] = lambda: self._actionGroupedResultsListing(
211 TestResultLogic.ksResultsGroupingTypeTestGroup,
212 TestResultLogic,
213 WuiGroupedResultList)
214
215 d[self.ksActionResultsGroupedByBuildRev] = lambda: self._actionGroupedResultsListing(
216 TestResultLogic.ksResultsGroupingTypeBuildRev,
217 TestResultLogic,
218 WuiGroupedResultList)
219
220 d[self.ksActionResultsGroupedByTestBox] = lambda: self._actionGroupedResultsListing(
221 TestResultLogic.ksResultsGroupingTypeTestBox,
222 TestResultLogic,
223 WuiGroupedResultList)
224
225 d[self.ksActionResultsGroupedByTestCase] = lambda: self._actionGroupedResultsListing(
226 TestResultLogic.ksResultsGroupingTypeTestCase,
227 TestResultLogic,
228 WuiGroupedResultList)
229
230 d[self.ksActionResultsGroupedBySchedGroup] = lambda: self._actionGroupedResultsListing(
231 TestResultLogic.ksResultsGroupingTypeSchedGroup,
232 TestResultLogic,
233 WuiGroupedResultList)
234
235 d[self.ksActionTestResultDetails] = self._actionTestResultDetails;
236
237 d[self.ksActionTestResultFailureAdd] = self._actionTestResultFailureAdd;
238 d[self.ksActionTestResultFailureAddPost] = self._actionTestResultFailureAddPost;
239 d[self.ksActionTestResultFailureDetails] = self._actionTestResultFailureDetails;
240 d[self.ksActionTestResultFailureEdit] = self._actionTestResultFailureEdit;
241 d[self.ksActionTestResultFailureEditPost] = self._actionTestResultFailureEditPost;
242
243 d[self.ksActionViewLog] = self.actionViewLog;
244 d[self.ksActionGetFile] = self.actionGetFile;
245 from testmanager.webui.wuireport import WuiReportSummary, WuiReportSuccessRate, WuiReportFailureReasons;
246 d[self.ksActionReportSummary] = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSummary);
247 d[self.ksActionReportRate] = lambda: self._actionGenericReport(ReportLazyModel, WuiReportSuccessRate);
248 d[self.ksActionReportFailureReasons] = lambda: self._actionGenericReport(ReportLazyModel, WuiReportFailureReasons);
249 d[self.ksActionGraphWiz] = self._actionGraphWiz;
250 d[self.ksActionVcsHistoryTooltip] = self._actionVcsHistoryTooltip;
251
252
253 #
254 # Popupate the menus.
255 #
256
257 # Additional URL parameters keeping for time navigation.
258 sExtraTimeNav = ''
259 dCurParams = oSrvGlue.getParameters()
260 if dCurParams is not None:
261 asActionUrlExtras = [ self.ksParamItemsPerPage, self.ksParamEffectiveDate, self.ksParamEffectivePeriod, ];
262 for sExtraParam in asActionUrlExtras:
263 if sExtraParam in dCurParams:
264 sExtraTimeNav += '&%s' % webutils.encodeUrlParams({sExtraParam: dCurParams[sExtraParam]})
265
266 # Shorthand to keep within margins.
267 sActUrlBase = self._sActionUrlBase;
268
269 self._aaoMenus = \
270 [
271 [
272 'Inbox', sActUrlBase + 'TODO', ## @todo list of failures that needs categorizing.
273 []
274 ],
275 [
276 'Reports', sActUrlBase + self.ksActionReportSummary,
277 [
278 [ 'Summary', sActUrlBase + self.ksActionReportSummary ],
279 [ 'Success Rate', sActUrlBase + self.ksActionReportRate ],
280 [ 'Failure Reasons', sActUrlBase + self.ksActionReportFailureReasons ],
281 ]
282 ],
283 [
284 'Test Results', sActUrlBase + self.ksActionResultsUnGrouped + sExtraTimeNav,
285 [
286 [ 'Ungrouped results', sActUrlBase + self.ksActionResultsUnGrouped + sExtraTimeNav ],
287 [ 'Grouped by Scheduling Group', sActUrlBase + self.ksActionResultsGroupedBySchedGroup + sExtraTimeNav ],
288 [ 'Grouped by Test Group', sActUrlBase + self.ksActionResultsGroupedByTestGroup + sExtraTimeNav ],
289 [ 'Grouped by TestBox', sActUrlBase + self.ksActionResultsGroupedByTestBox + sExtraTimeNav ],
290 [ 'Grouped by Test Case', sActUrlBase + self.ksActionResultsGroupedByTestCase + sExtraTimeNav ],
291 [ 'Grouped by Revision', sActUrlBase + self.ksActionResultsGroupedByBuildRev + sExtraTimeNav ],
292 ]
293 ],
294 [
295 '> Admin', 'admin.py?' + webutils.encodeUrlParams(self._dDbgParams), []
296 ],
297 ];
298
299
300 def _actionDefault(self):
301 """Show the default admin page."""
302 from testmanager.webui.wuitestresult import WuiGroupedResultList;
303 self._sAction = self.ksActionResultsUnGrouped
304 return self._actionGroupedResultsListing(TestResultLogic.ksResultsGroupingTypeNone,
305 TestResultLogic,
306 WuiGroupedResultList)
307
308
309 #
310 # Navigation bar stuff
311 #
312
313 def _generateSortBySelector(self, dParams, sPreamble, sPostamble):
314 """
315 Generate HTML code for the sort by selector.
316 """
317 if self.ksParamTestResultsSortBy in dParams:
318 enmResultSortBy = dParams[self.ksParamTestResultsSortBy];
319 del dParams[self.ksParamTestResultsSortBy];
320 else:
321 enmResultSortBy = TestResultLogic.ksResultsSortByRunningAndStart;
322
323 sHtmlSortBy = '<form name="TimeForm" method="GET"> Sort by\n';
324 sHtmlSortBy += sPreamble;
325 sHtmlSortBy += '\n <select name="%s" onchange="window.location=' % (self.ksParamTestResultsSortBy,);
326 sHtmlSortBy += '\'?%s&%s=\' + ' % (webutils.encodeUrlParams(dParams), self.ksParamTestResultsSortBy)
327 sHtmlSortBy += 'this.options[this.selectedIndex].value;" title="Sorting by">\n'
328
329 fSelected = False;
330 for enmCode, sTitle in TestResultLogic.kaasResultsSortByTitles:
331 if enmCode == enmResultSortBy:
332 fSelected = True;
333 sHtmlSortBy += ' <option value="%s"%s>%s</option>\n' \
334 % (enmCode, ' selected="selected"' if enmCode == enmResultSortBy else '', sTitle,);
335 assert fSelected;
336 sHtmlSortBy += ' </select>\n';
337 sHtmlSortBy += sPostamble;
338 sHtmlSortBy += '\n</form>\n'
339 return sHtmlSortBy;
340
341 def _generateStatusSelector(self, dParams, fOnlyFailures):
342 """
343 Generate HTML code for the status code selector. Currently very simple.
344 """
345 dParams[self.ksParamOnlyFailures] = not fOnlyFailures;
346 return WuiTmLink('Show all results' if fOnlyFailures else 'Only show failed tests', '', dParams,
347 fBracketed = False).toHtml();
348
349 def _generateTimeSelector(self, dParams, sPreamble, sPostamble):
350 """
351 Generate HTML code for time selector.
352 """
353
354 if WuiDispatcherBase.ksParamEffectiveDate in dParams:
355 tsEffective = dParams[WuiDispatcherBase.ksParamEffectiveDate]
356 del dParams[WuiDispatcherBase.ksParamEffectiveDate]
357 else:
358 tsEffective = ''
359
360 # Forget about page No when changing a period
361 if WuiDispatcherBase.ksParamPageNo in dParams:
362 del dParams[WuiDispatcherBase.ksParamPageNo]
363
364 sHtmlTimeSelector = '<form name="TimeForm" method="GET">\n'
365 sHtmlTimeSelector += sPreamble;
366 sHtmlTimeSelector += '\n <select name="%s" onchange="window.location=' % WuiDispatcherBase.ksParamEffectiveDate
367 sHtmlTimeSelector += '\'?%s&%s=\' + ' % (webutils.encodeUrlParams(dParams), WuiDispatcherBase.ksParamEffectiveDate)
368 sHtmlTimeSelector += 'this.options[this.selectedIndex].value;" title="Effective date">\n'
369
370 aoWayBackPoints = [
371 ('+0000-00-00 00:00:00.00', 'Now', ' title="Present Day. Present Time."'), # lain :)
372
373 ('-0000-00-00 01:00:00.00', 'One hour ago', ''),
374 ('-0000-00-00 02:00:00.00', 'Two hours ago', ''),
375 ('-0000-00-00 03:00:00.00', 'Three hours ago', ''),
376
377 ('-0000-00-01 00:00:00.00', 'One day ago', ''),
378 ('-0000-00-02 00:00:00.00', 'Two days ago', ''),
379 ('-0000-00-03 00:00:00.00', 'Three days ago', ''),
380
381 ('-0000-00-07 00:00:00.00', 'One week ago', ''),
382 ('-0000-00-14 00:00:00.00', 'Two weeks ago', ''),
383 ('-0000-00-21 00:00:00.00', 'Three weeks ago', ''),
384
385 ('-0000-01-00 00:00:00.00', 'One month ago', ''),
386 ('-0000-02-00 00:00:00.00', 'Two months ago', ''),
387 ('-0000-03-00 00:00:00.00', 'Three months ago', ''),
388 ('-0000-04-00 00:00:00.00', 'Four months ago', ''),
389 ('-0000-05-00 00:00:00.00', 'Five months ago', ''),
390 ('-0000-06-00 00:00:00.00', 'Half a year ago', ''),
391
392 ('-0001-00-00 00:00:00.00', 'One year ago', ''),
393 ]
394 fSelected = False;
395 for sTimestamp, sWayBackPointCaption, sExtraAttrs in aoWayBackPoints:
396 if sTimestamp == tsEffective:
397 fSelected = True;
398 sHtmlTimeSelector += ' <option value="%s"%s%s>%s</option>\n' \
399 % (webutils.quoteUrl(sTimestamp),
400 ' selected="selected"' if sTimestamp == tsEffective else '',
401 sExtraAttrs, sWayBackPointCaption)
402 if not fSelected and tsEffective != '':
403 sHtmlTimeSelector += ' <option value="%s" selected>%s</option>\n' \
404 % (webutils.quoteUrl(tsEffective), tsEffective)
405
406 sHtmlTimeSelector += ' </select>\n';
407 sHtmlTimeSelector += sPostamble;
408 sHtmlTimeSelector += '\n</form>\n'
409
410 return sHtmlTimeSelector
411
412 def _generateTimeWalker(self, dParams, tsEffective, sCurPeriod):
413 """
414 Generates HTML code for walking back and forth in time.
415 """
416 # Have to do some math here. :-/
417 if tsEffective is None:
418 self._oDb.execute('SELECT CURRENT_TIMESTAMP - \'' + sCurPeriod + '\'::interval');
419 tsNext = None;
420 tsPrev = self._oDb.fetchOne()[0];
421 else:
422 self._oDb.execute('SELECT %s::TIMESTAMP - \'' + sCurPeriod + '\'::interval,\n'
423 ' %s::TIMESTAMP + \'' + sCurPeriod + '\'::interval',
424 (tsEffective, tsEffective,));
425 tsPrev, tsNext = self._oDb.fetchOne();
426
427 # Forget about page No when changing a period
428 if WuiDispatcherBase.ksParamPageNo in dParams:
429 del dParams[WuiDispatcherBase.ksParamPageNo]
430
431 # Format.
432 dParams[WuiDispatcherBase.ksParamEffectiveDate] = str(tsPrev);
433 sPrev = '<a href="?%s" title="One period earlier">&lt;&lt;</a>&nbsp;&nbsp;' \
434 % (webutils.encodeUrlParams(dParams),);
435
436 if tsNext is not None:
437 dParams[WuiDispatcherBase.ksParamEffectiveDate] = str(tsNext);
438 sNext = '&nbsp;&nbsp;<a href="?%s" title="One period later">&gt;&gt;</a>' \
439 % (webutils.encodeUrlParams(dParams),);
440 else:
441 sNext = '&nbsp;&nbsp;&gt;&gt;';
442
443 return self._generateTimeSelector(self.getParameters(), sPrev, sNext);
444
445 def _generateResultPeriodSelector(self, dParams, sCurPeriod):
446 """
447 Generate HTML code for result period selector.
448 """
449
450 if self.ksParamEffectivePeriod in dParams:
451 del dParams[self.ksParamEffectivePeriod];
452
453 # Forget about page No when changing a period
454 if WuiDispatcherBase.ksParamPageNo in dParams:
455 del dParams[WuiDispatcherBase.ksParamPageNo]
456
457 sHtmlPeriodSelector = '<form name="PeriodForm" method="GET">\n'
458 sHtmlPeriodSelector += ' Period is\n'
459 sHtmlPeriodSelector += ' <select name="%s" onchange="window.location=' % self.ksParamEffectivePeriod
460 sHtmlPeriodSelector += '\'?%s&%s=\' + ' % (webutils.encodeUrlParams(dParams), self.ksParamEffectivePeriod)
461 sHtmlPeriodSelector += 'this.options[this.selectedIndex].value;">\n'
462
463 for sPeriodValue, sPeriodCaption, _ in self.kaoResultPeriods:
464 sHtmlPeriodSelector += ' <option value="%s"%s>%s</option>\n' \
465 % (webutils.quoteUrl(sPeriodValue),
466 ' selected="selected"' if sPeriodValue == sCurPeriod else '',
467 sPeriodCaption)
468
469 sHtmlPeriodSelector += ' </select>\n' \
470 '</form>\n'
471
472 return sHtmlPeriodSelector
473
474 def _generateGroupContentSelector(self, aoGroupMembers, iCurrentMember, sAltAction):
475 """
476 Generate HTML code for group content selector.
477 """
478
479 dParams = self.getParameters()
480
481 if self.ksParamGroupMemberId in dParams:
482 del dParams[self.ksParamGroupMemberId]
483
484 if sAltAction is not None:
485 if self.ksParamAction in dParams:
486 del dParams[self.ksParamAction];
487 dParams[self.ksParamAction] = sAltAction;
488
489 sHtmlSelector = '<form name="GroupContentForm" method="GET">\n'
490 sHtmlSelector += ' <select name="%s" onchange="window.location=' % self.ksParamGroupMemberId
491 sHtmlSelector += '\'?%s&%s=\' + ' % (webutils.encodeUrlParams(dParams), self.ksParamGroupMemberId)
492 sHtmlSelector += 'this.options[this.selectedIndex].value;">\n'
493
494 sHtmlSelector += '<option value="-1">All</option>\n'
495
496 for iGroupMemberId, sGroupMemberName in aoGroupMembers:
497 if iGroupMemberId is not None:
498 sHtmlSelector += ' <option value="%s"%s>%s</option>\n' \
499 % (iGroupMemberId,
500 ' selected="selected"' if iGroupMemberId == iCurrentMember else '',
501 sGroupMemberName)
502
503 sHtmlSelector += ' </select>\n' \
504 '</form>\n'
505
506 return sHtmlSelector
507
508 def _generatePagesSelector(self, dParams, cItems, cItemsPerPage, iPage):
509 """
510 Generate HTML code for pages (1, 2, 3 ... N) selector
511 """
512
513 if WuiDispatcherBase.ksParamPageNo in dParams:
514 del dParams[WuiDispatcherBase.ksParamPageNo]
515
516 sHrefPtr = '<a href="?%s&%s=' % (webutils.encodeUrlParams(dParams).replace('%', '%%'),
517 WuiDispatcherBase.ksParamPageNo)
518 sHrefPtr += '%d">%s</a>'
519
520 cNumOfPages = (cItems + cItemsPerPage - 1) / cItemsPerPage;
521 cPagesToDisplay = 10
522 cPagesRangeStart = iPage - cPagesToDisplay / 2 \
523 if not iPage - cPagesToDisplay / 2 < 0 else 0
524 cPagesRangeEnd = cPagesRangeStart + cPagesToDisplay \
525 if not cPagesRangeStart + cPagesToDisplay > cNumOfPages else cNumOfPages
526 # Adjust pages range
527 if cNumOfPages < cPagesToDisplay:
528 cPagesRangeStart = 0
529 cPagesRangeEnd = cNumOfPages
530
531 # 1 2 3 4...
532 sHtmlPager = '&nbsp;\n'.join(sHrefPtr % (x, str(x + 1)) if x != iPage else str(x + 1)
533 for x in range(cPagesRangeStart, cPagesRangeEnd))
534 if cPagesRangeStart > 0:
535 sHtmlPager = '%s&nbsp; ... &nbsp;\n' % (sHrefPtr % (0, str(1))) + sHtmlPager
536 if cPagesRangeEnd < cNumOfPages:
537 sHtmlPager += ' ... %s\n' % (sHrefPtr % (cNumOfPages, str(cNumOfPages + 1)))
538
539 # Prev/Next (using << >> because &laquo; and &raquo are too tiny).
540 if iPage > 0:
541 dParams[WuiDispatcherBase.ksParamPageNo] = iPage - 1
542 sHtmlPager = ('<a title="Previous page" href="?%s">&lt;&lt;</a>&nbsp;&nbsp;\n'
543 % (webutils.encodeUrlParams(dParams), )) \
544 + sHtmlPager;
545 else:
546 sHtmlPager = '&lt;&lt;&nbsp;&nbsp;\n' + sHtmlPager
547
548 if iPage + 1 < cNumOfPages:
549 dParams[WuiDispatcherBase.ksParamPageNo] = iPage + 1
550 sHtmlPager += '\n&nbsp; <a title="Next page" href="?%s">&gt;&gt;</a>\n' % (webutils.encodeUrlParams(dParams),)
551 else:
552 sHtmlPager += '\n&nbsp; &gt;&gt;\n'
553
554 return sHtmlPager
555
556 def _generateItemPerPageSelector(self, dParams, cItemsPerPage):
557 """
558 Generate HTML code for items per page selector
559 """
560
561 if WuiDispatcherBase.ksParamItemsPerPage in dParams:
562 del dParams[WuiDispatcherBase.ksParamItemsPerPage]
563
564 # Forced reset of the page number
565 dParams[WuiDispatcherBase.ksParamPageNo] = 0
566 sHtmlItemsPerPageSelector = '<form name="AgesPerPageForm" method="GET">\n' \
567 ' Max <select name="%s" onchange="window.location=\'?%s&%s=\' + ' \
568 'this.options[this.selectedIndex].value;" title="Max items per page">\n' \
569 % (WuiDispatcherBase.ksParamItemsPerPage,
570 webutils.encodeUrlParams(dParams),
571 WuiDispatcherBase.ksParamItemsPerPage)
572
573 aiItemsPerPage = [16, 32, 64, 128, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096];
574 for iItemsPerPage in aiItemsPerPage:
575 sHtmlItemsPerPageSelector += ' <option value="%d" %s>%d</option>\n' \
576 % (iItemsPerPage,
577 'selected="selected"' if iItemsPerPage == cItemsPerPage else '',
578 iItemsPerPage)
579 sHtmlItemsPerPageSelector += ' </select> items per page\n' \
580 '</form>\n'
581
582 return sHtmlItemsPerPageSelector
583
584 def _generateResultNavigation(self, cItems, cItemsPerPage, iPage, tsEffective, sCurPeriod, fOnlyFailures,
585 sHtmlMemberSelector):
586 """ Make custom time navigation bar for the results. """
587
588 # Generate the elements.
589 sHtmlStatusSelector = self._generateStatusSelector(self.getParameters(), fOnlyFailures);
590 sHtmlSortBySelector = self._generateSortBySelector(self.getParameters(), '', sHtmlStatusSelector);
591 sHtmlPeriodSelector = self._generateResultPeriodSelector(self.getParameters(), sCurPeriod)
592 sHtmlTimeWalker = self._generateTimeWalker(self.getParameters(), tsEffective, sCurPeriod);
593
594 if cItems > 0:
595 sHtmlPager = self._generatePagesSelector(self.getParameters(), cItems, cItemsPerPage, iPage)
596 sHtmlItemsPerPageSelector = self._generateItemPerPageSelector(self.getParameters(), cItemsPerPage)
597 else:
598 sHtmlPager = ''
599 sHtmlItemsPerPageSelector = ''
600
601 # Generate navigation bar
602 sHtml = '<table width=100%>\n' \
603 '<tr>\n' \
604 ' <td width=30%>' + sHtmlMemberSelector + '</td>\n' \
605 ' <td width=40% align=center>' + sHtmlTimeWalker + '</td>' \
606 ' <td width=30% align=right>\n' + sHtmlPeriodSelector + '</td>\n' \
607 '</tr>\n' \
608 '<tr>\n' \
609 ' <td width=30%>' + sHtmlSortBySelector + '</td>\n' \
610 ' <td width=40% align=center>\n' + sHtmlPager + '</td>\n' \
611 ' <td width=30% align=right>\n' + sHtmlItemsPerPageSelector + '</td>\n'\
612 '</tr>\n' \
613 '</table>\n'
614
615 return sHtml
616
617 def _generateReportNavigation(self, tsEffective, cHoursPerPeriod, cPeriods):
618 """ Make time navigation bar for the reports. """
619
620 # The period length selector.
621 dParams = self.getParameters();
622 if WuiMain.ksParamReportPeriodInHours in dParams:
623 del dParams[WuiMain.ksParamReportPeriodInHours];
624 sHtmlPeriodLength = '';
625 sHtmlPeriodLength += '<form name="ReportPeriodInHoursForm" method="GET">\n' \
626 ' Period length <select name="%s" onchange="window.location=\'?%s&%s=\' + ' \
627 'this.options[this.selectedIndex].value;" title="Statistics period length in hours.">\n' \
628 % (WuiMain.ksParamReportPeriodInHours,
629 webutils.encodeUrlParams(dParams),
630 WuiMain.ksParamReportPeriodInHours)
631 for cHours in [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 18, 24, 48, 72, 96, 120, 144, 168 ]:
632 sHtmlPeriodLength += ' <option value="%d"%s>%d hour%s</option>\n' \
633 % (cHours, 'selected="selected"' if cHours == cHoursPerPeriod else '', cHours,
634 's' if cHours > 1 else '');
635 sHtmlPeriodLength += ' </select>\n' \
636 '</form>\n'
637
638 # The period count selector.
639 dParams = self.getParameters();
640 if WuiMain.ksParamReportPeriods in dParams:
641 del dParams[WuiMain.ksParamReportPeriods];
642 sHtmlCountOfPeriods = '';
643 sHtmlCountOfPeriods += '<form name="ReportPeriodsForm" method="GET">\n' \
644 ' Periods <select name="%s" onchange="window.location=\'?%s&%s=\' + ' \
645 'this.options[this.selectedIndex].value;" title="Statistics periods to report.">\n' \
646 % (WuiMain.ksParamReportPeriods,
647 webutils.encodeUrlParams(dParams),
648 WuiMain.ksParamReportPeriods)
649 for cCurPeriods in range(2, 43):
650 sHtmlCountOfPeriods += ' <option value="%d"%s>%d</option>\n' \
651 % (cCurPeriods, 'selected="selected"' if cCurPeriods == cPeriods else '', cCurPeriods);
652 sHtmlCountOfPeriods += ' </select>\n' \
653 '</form>\n'
654
655 # The time walker.
656 sHtmlTimeWalker = self._generateTimeWalker(self.getParameters(), tsEffective, '%d hours' % (cHoursPerPeriod));
657
658 # Combine them all.
659 sHtml = '<table width=100%>\n' \
660 ' <tr>\n' \
661 ' <td width=30% align="center">\n' + sHtmlPeriodLength + '</td>\n' \
662 ' <td width=40% align="center">\n' + sHtmlTimeWalker + '</td>' \
663 ' <td width=30% align="center">\n' + sHtmlCountOfPeriods + '</td>\n' \
664 ' </tr>\n' \
665 '</table>\n';
666 return sHtml;
667
668 #
669 # The rest of stuff
670 #
671
672 def _actionGroupedResultsListing( #pylint: disable=R0914
673 self,
674 enmResultsGroupingType,
675 oResultsLogicType,
676 oResultsListContentType):
677 """
678 Override generic listing action.
679
680 oLogicType implements fetchForListing.
681 oListContentType is a child of WuiListContentBase.
682 """
683 cItemsPerPage = self.getIntParam(self.ksParamItemsPerPage, iMin = 2, iMax = 9999, iDefault = 128);
684 iPage = self.getIntParam(self.ksParamPageNo, iMin = 0, iMax = 999999, iDefault = 0);
685 tsEffective = self.getEffectiveDateParam();
686 iGroupMemberId = self.getIntParam(self.ksParamGroupMemberId, iMin = -1, iMax = 999999, iDefault = -1);
687 fOnlyFailures = self.getBoolParam(self.ksParamOnlyFailures, fDefault = False);
688 enmResultSortBy = self.getStringParam(self.ksParamTestResultsSortBy,
689 asValidValues = TestResultLogic.kasResultsSortBy,
690 sDefault = TestResultLogic.ksResultsSortByRunningAndStart);
691
692 # Get testing results period and validate it
693 asValidValues = [x for (x, _, _) in self.kaoResultPeriods]
694 sCurPeriod = self.getStringParam(self.ksParamEffectivePeriod, asValidValues = asValidValues,
695 sDefault = self.ksResultPeriodDefault)
696 assert sCurPeriod != ''; # Impossible!
697
698 self._checkForUnknownParameters()
699
700 #
701 # Fetch the group members.
702 #
703 # If no grouping is selected, we'll fill the the grouping combo with
704 # testboxes just to avoid having completely useless combo box.
705 #
706 oTrLogic = TestResultLogic(self._oDb);
707 sAltSelectorAction = None;
708 if enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeNone \
709 or enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeTestBox:
710 aoTmp = oTrLogic.getTestBoxes(tsNow = tsEffective, sPeriod = sCurPeriod)
711 aoGroupMembers = sorted(list(set([ (x.idTestBox, '%s (%s)' % (x.sName, str(x.ip))) for x in aoTmp ])),
712 reverse = False, key = lambda asData: asData[1])
713
714 if enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeTestBox:
715 self._sPageTitle = 'Grouped by Test Box';
716 else:
717 self._sPageTitle = 'Ungrouped results';
718 sAltSelectorAction = self.ksActionResultsGroupedByTestBox;
719 aoGroupMembers.insert(0, [None, None]); # The "All" member.
720
721 elif enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeTestGroup:
722 aoTmp = oTrLogic.getTestGroups(tsNow = tsEffective, sPeriod = sCurPeriod);
723 aoGroupMembers = sorted(list(set([ (x.idTestGroup, x.sName ) for x in aoTmp ])),
724 reverse = False, key = lambda asData: asData[1])
725 self._sPageTitle = 'Grouped by Test Group'
726
727 elif enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeBuildRev:
728 aoTmp = oTrLogic.getBuilds(tsNow = tsEffective, sPeriod = sCurPeriod)
729 aoGroupMembers = sorted(list(set([ (x.iRevision, '%s.%d' % (x.oCat.sBranch, x.iRevision)) for x in aoTmp ])),
730 reverse = True, key = lambda asData: asData[0])
731 self._sPageTitle = 'Grouped by Build'
732
733 elif enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeTestCase:
734 aoTmp = oTrLogic.getTestCases(tsNow = tsEffective, sPeriod = sCurPeriod)
735 aoGroupMembers = sorted(list(set([ (x.idTestCase, '%s' % x.sName) for x in aoTmp ])),
736 reverse = False, key = lambda asData: asData[1])
737 self._sPageTitle = 'Grouped by Test Case'
738
739 elif enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeSchedGroup:
740 aoTmp = oTrLogic.getSchedGroups(tsNow = tsEffective, sPeriod = sCurPeriod)
741 aoGroupMembers = sorted(list(set([ (x.idSchedGroup, '%s' % x.sName) for x in aoTmp ])),
742 reverse = False, key = lambda asData: asData[1])
743 self._sPageTitle = 'Grouped by Scheduling Group'
744
745 else:
746 raise TMExceptionBase('Unknown grouping type')
747
748 _sPageBody = ''
749 oContent = None
750 cEntriesMax = 0
751 _dParams = self.getParameters()
752 for idMember, sMemberName in aoGroupMembers:
753 #
754 # Count and fetch entries to be displayed.
755 #
756
757 # Skip group members that were not specified.
758 if idMember != iGroupMemberId \
759 and ( (idMember is not None and enmResultsGroupingType == TestResultLogic.ksResultsGroupingTypeNone)
760 or (iGroupMemberId > 0 and enmResultsGroupingType != TestResultLogic.ksResultsGroupingTypeNone) ):
761 continue
762
763 oResultLogic = oResultsLogicType(self._oDb);
764 cEntries = oResultLogic.getEntriesCount(tsNow = tsEffective,
765 sInterval = sCurPeriod,
766 enmResultsGroupingType = enmResultsGroupingType,
767 iResultsGroupingValue = idMember,
768 fOnlyFailures = fOnlyFailures);
769 if cEntries == 0: # Do not display empty groups
770 continue
771 aoEntries = oResultLogic.fetchResultsForListing(iPage * cItemsPerPage,
772 cItemsPerPage,
773 tsNow = tsEffective,
774 sInterval = sCurPeriod,
775 enmResultSortBy = enmResultSortBy,
776 enmResultsGroupingType = enmResultsGroupingType,
777 iResultsGroupingValue = idMember,
778 fOnlyFailures = fOnlyFailures);
779 cEntriesMax = max(cEntriesMax, cEntries)
780
781 #
782 # Format them.
783 #
784 oContent = oResultsListContentType(aoEntries,
785 cEntries,
786 iPage,
787 cItemsPerPage,
788 tsEffective,
789 fnDPrint = self._oSrvGlue.dprint,
790 oDisp = self)
791
792 (_, sHtml) = oContent.show(fShowNavigation = False)
793 if sMemberName is not None:
794 _sPageBody += '<table width=100%><tr><td>'
795
796 _dParams[self.ksParamGroupMemberId] = idMember
797 sLink = WuiTmLink(sMemberName, '', _dParams, fBracketed = False).toHtml()
798
799 _sPageBody += '<h2>%s (%d)</h2></td>' % (sLink, cEntries)
800 _sPageBody += '<td><br></td>'
801 _sPageBody += '</tr></table>'
802 _sPageBody += sHtml
803 _sPageBody += '<br>'
804
805 #
806 # Complete the page by slapping navigation controls at the top and
807 # bottom of it.
808 #
809 sHtmlNavigation = self._generateResultNavigation(cEntriesMax, cItemsPerPage, iPage,
810 tsEffective, sCurPeriod, fOnlyFailures,
811 self._generateGroupContentSelector(aoGroupMembers, iGroupMemberId,
812 sAltSelectorAction));
813 if cEntriesMax > 0:
814 self._sPageBody = sHtmlNavigation + _sPageBody + sHtmlNavigation;
815 else:
816 self._sPageBody = sHtmlNavigation + '<p align="center"><i>No data to display</i></p>\n';
817 return True;
818
819 def _generatePage(self):
820 """Override parent handler in order to change page title."""
821 if self._sPageTitle is not None:
822 self._sPageTitle = 'Test Results - ' + self._sPageTitle
823
824 return WuiDispatcherBase._generatePage(self)
825
826 def _actionTestResultDetails(self):
827 """Show test case execution result details."""
828 from testmanager.webui.wuitestresult import WuiTestResult;
829
830 self._sTemplate = 'template-details.html';
831 idTestSet = self.getIntParam(TestSetData.ksParam_idTestSet);
832 self._checkForUnknownParameters()
833
834 oTestSetData = TestSetData().initFromDbWithId(self._oDb, idTestSet);
835 try:
836 (oTestResultTree, _) = TestResultLogic(self._oDb).fetchResultTree(idTestSet);
837 except TMTooManyRows:
838 (oTestResultTree, _) = TestResultLogic(self._oDb).fetchResultTree(idTestSet, 2);
839 oBuildDataEx = BuildDataEx().initFromDbWithId(self._oDb, oTestSetData.idBuild, oTestSetData.tsCreated);
840 try: oBuildValidationKitDataEx = BuildDataEx().initFromDbWithId(self._oDb, oTestSetData.idBuildTestSuite,
841 oTestSetData.tsCreated);
842 except: oBuildValidationKitDataEx = None;
843 oTestBoxData = TestBoxData().initFromDbWithGenId(self._oDb, oTestSetData.idGenTestBox);
844 oTestGroupData = TestGroupData().initFromDbWithId(self._oDb, ## @todo This bogus time wise. Bad DB design?
845 oTestSetData.idTestGroup, oTestSetData.tsCreated);
846 oTestCaseDataEx = TestCaseDataEx().initFromDbWithGenId(self._oDb, oTestSetData.idGenTestCase,
847 oTestSetData.tsConfig);
848 oTestCaseArgsDataEx = TestCaseArgsDataEx().initFromDbWithGenIdEx(self._oDb, oTestSetData.idGenTestCaseArgs,
849 oTestSetData.tsConfig);
850
851 oContent = WuiTestResult(oDisp = self, fnDPrint = self._oSrvGlue.dprint);
852 (self._sPageTitle, self._sPageBody) = oContent.showTestCaseResultDetails(oTestResultTree,
853 oTestSetData,
854 oBuildDataEx,
855 oBuildValidationKitDataEx,
856 oTestBoxData,
857 oTestGroupData,
858 oTestCaseDataEx,
859 oTestCaseArgsDataEx);
860 return True
861
862 def _actionTestResultFailureAdd(self):
863 """ Pro forma. """
864 from testmanager.core.testresults import TestResultFailureData;
865 from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
866 return self._actionGenericFormAdd(TestResultFailureData, WuiTestResultFailure);
867
868 def _actionTestResultFailureAddPost(self):
869 """Add test result failure result"""
870 from testmanager.core.testresults import TestResultFailureLogic, TestResultFailureData;
871 from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
872 if self.ksParamRedirectTo not in self._dParams:
873 raise WuiException('Missing parameter ' + self.ksParamRedirectTo);
874
875 return self._actionGenericFormAddPost(TestResultFailureData, TestResultFailureLogic,
876 WuiTestResultFailure, self.ksActionResultsUnGrouped);
877
878 def _actionTestResultFailureDetails(self):
879 """ Pro forma. """
880 from testmanager.core.testresults import TestResultFailureLogic, TestResultFailureData;
881 from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
882 return self._actionGenericFormDetails(TestResultFailureData, TestResultFailureLogic,
883 WuiTestResultFailure, 'idTestResult');
884
885 def _actionTestResultFailureEdit(self):
886 """ Pro forma. """
887 from testmanager.core.testresults import TestResultFailureData;
888 from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
889 return self._actionGenericFormEdit(TestResultFailureData, WuiTestResultFailure,
890 TestResultFailureData.ksParam_idTestResult);
891
892 def _actionTestResultFailureEditPost(self):
893 """Edit test result failure result"""
894 from testmanager.core.testresults import TestResultFailureLogic, TestResultFailureData;
895 from testmanager.webui.wuitestresultfailure import WuiTestResultFailure;
896 if self.ksParamRedirectTo not in self._dParams:
897 raise WuiException('Missing parameter ' + self.ksParamRedirectTo);
898
899 return self._actionGenericFormEditPost(TestResultFailureData, TestResultFailureLogic,
900 WuiTestResultFailure, self.ksActionResultsUnGrouped);
901
902 def actionViewLog(self):
903 """
904 Log viewer action.
905 """
906 from testmanager.webui.wuilogviewer import WuiLogViewer;
907 self._sTemplate = 'template-details.html'; ## @todo create new template (background color, etc)
908 idTestSet = self.getIntParam(self.ksParamLogSetId, iMin = 1);
909 idLogFile = self.getIntParam(self.ksParamLogFileId, iMin = 0, iDefault = 0);
910 cbChunk = self.getIntParam(self.ksParamLogChunkSize, iMin = 256, iMax = 16777216, iDefault = 65536);
911 iChunk = self.getIntParam(self.ksParamLogChunkNo, iMin = 0,
912 iMax = config.g_kcMbMaxMainLog * 1048576 / cbChunk, iDefault = 0);
913 self._checkForUnknownParameters();
914
915 oTestSet = TestSetData().initFromDbWithId(self._oDb, idTestSet);
916 if idLogFile == 0:
917 oTestFile = TestResultFileDataEx().initFakeMainLog(oTestSet);
918 else:
919 oTestFile = TestSetLogic(self._oDb).getFile(idTestSet, idLogFile);
920 if oTestFile.sMime not in [ 'text/plain',]:
921 raise WuiException('The log view does not display files of type: %s' % (oTestFile.sMime,));
922
923 oContent = WuiLogViewer(oTestSet, oTestFile, cbChunk, iChunk, oDisp = self, fnDPrint = self._oSrvGlue.dprint);
924 (self._sPageTitle, self._sPageBody) = oContent.show();
925 return True;
926
927 def actionGetFile(self):
928 """
929 Get file action.
930 """
931 idTestSet = self.getIntParam(self.ksParamGetFileSetId, iMin = 1);
932 idFile = self.getIntParam(self.ksParamGetFileId, iMin = 0, iDefault = 0);
933 fDownloadIt = self.getBoolParam(self.ksParamGetFileDownloadIt, fDefault = True);
934 self._checkForUnknownParameters();
935
936 #
937 # Get the file info and open it.
938 #
939 oTestSet = TestSetData().initFromDbWithId(self._oDb, idTestSet);
940 if idFile == 0:
941 oTestFile = TestResultFileDataEx().initFakeMainLog(oTestSet);
942 else:
943 oTestFile = TestSetLogic(self._oDb).getFile(idTestSet, idFile);
944
945 (oFile, oSizeOrError, _) = oTestSet.openFile(oTestFile.sFile, 'rb');
946 if oFile is None:
947 raise Exception(oSizeOrError);
948
949 #
950 # Send the file.
951 #
952 self._oSrvGlue.setHeaderField('Content-Type', oTestFile.getMimeWithEncoding());
953 if fDownloadIt:
954 self._oSrvGlue.setHeaderField('Content-Disposition', 'attachment; filename="TestSet-%d-%s"'
955 % (idTestSet, oTestFile.sFile,));
956 while True:
957 abChunk = oFile.read(262144);
958 if len(abChunk) == 0:
959 break;
960 self._oSrvGlue.writeRaw(abChunk);
961 return self.ksDispatchRcAllDone;
962
963 def _actionGenericReport(self, oModelType, oReportType):
964 """
965 Generic report action.
966 oReportType is a child of WuiReportContentBase.
967 oModelType is a child of ReportModelBase.
968 """
969 tsEffective = self.getEffectiveDateParam();
970 cPeriods = self.getIntParam(self.ksParamReportPeriods, iMin = 2, iMax = 99, iDefault = 7);
971 cHoursPerPeriod = self.getIntParam(self.ksParamReportPeriodInHours, iMin = 1, iMax = 168, iDefault = 24);
972 sSubject = self.getStringParam(self.ksParamReportSubject, ReportModelBase.kasSubjects,
973 ReportModelBase.ksSubEverything);
974 if sSubject == ReportModelBase.ksSubEverything:
975 aidSubjects = self.getListOfIntParams(self.ksParamReportSubjectIds, aiDefaults = []);
976 else:
977 aidSubjects = self.getListOfIntParams(self.ksParamReportSubjectIds, iMin = 1);
978 if aidSubjects is None:
979 raise WuiException('Missing parameter %s' % (self.ksParamReportSubjectIds,));
980 self._checkForUnknownParameters();
981
982 dParams = \
983 {
984 self.ksParamEffectiveDate: tsEffective,
985 self.ksParamReportPeriods: cPeriods,
986 self.ksParamReportPeriodInHours: cHoursPerPeriod,
987 self.ksParamReportSubject: sSubject,
988 self.ksParamReportSubjectIds: aidSubjects,
989 };
990
991 oModel = oModelType(self._oDb, tsEffective, cPeriods, cHoursPerPeriod, sSubject, aidSubjects);
992 oContent = oReportType(oModel, dParams, fSubReport = False, fnDPrint = self._oSrvGlue.dprint, oDisp = self);
993 (self._sPageTitle, self._sPageBody) = oContent.show();
994 sNavi = self._generateReportNavigation(tsEffective, cHoursPerPeriod, cPeriods);
995 self._sPageBody = sNavi + self._sPageBody;
996 return True;
997
998 def _actionGraphWiz(self):
999 """
1000 Graph wizard action.
1001 """
1002 from testmanager.webui.wuigraphwiz import WuiGraphWiz;
1003 self._sTemplate = 'template-graphwiz.html';
1004
1005 tsEffective = self.getEffectiveDateParam();
1006 cPeriods = self.getIntParam(self.ksParamReportPeriods, iMin = 1, iMax = 1, iDefault = 1); # Not needed yet.
1007 sTmp = self.getStringParam(self.ksParamReportPeriodInHours, sDefault = '3 weeks');
1008 (cHoursPerPeriod, sError) = utils.parseIntervalHours(sTmp);
1009 if sError is not None: raise WuiException(sError);
1010 asSubjectIds = self.getListOfStrParams(self.ksParamReportSubjectIds);
1011 sSubject = self.getStringParam(self.ksParamReportSubject, [ReportModelBase.ksSubEverything],
1012 ReportModelBase.ksSubEverything); # dummy
1013 aidTestBoxes = self.getListOfIntParams(self.ksParamGraphWizTestBoxIds, iMin = 1, aiDefaults = []);
1014 aidBuildCats = self.getListOfIntParams(self.ksParamGraphWizBuildCatIds, iMin = 1, aiDefaults = []);
1015 aidTestCases = self.getListOfIntParams(self.ksParamGraphWizTestCaseIds, iMin = 1, aiDefaults = []);
1016 fSepTestVars = self.getBoolParam(self.ksParamGraphWizSepTestVars, fDefault = False);
1017
1018 enmGraphImpl = self.getStringParam(self.ksParamGraphWizImpl, asValidValues = self.kasGraphWizImplValid,
1019 sDefault = self.ksGraphWizImpl_Default);
1020 cx = self.getIntParam(self.ksParamGraphWizWidth, iMin = 128, iMax = 8192, iDefault = 1280);
1021 cy = self.getIntParam(self.ksParamGraphWizHeight, iMin = 128, iMax = 8192, iDefault = int(cx * 5 / 16) );
1022 cDotsPerInch = self.getIntParam(self.ksParamGraphWizDpi, iMin = 64, iMax = 512, iDefault = 96);
1023 cPtFont = self.getIntParam(self.ksParamGraphWizFontSize, iMin = 6, iMax = 32, iDefault = 8);
1024 fErrorBarY = self.getBoolParam(self.ksParamGraphWizErrorBarY, fDefault = False);
1025 cMaxErrorBarY = self.getIntParam(self.ksParamGraphWizMaxErrorBarY, iMin = 8, iMax = 9999999, iDefault = 18);
1026 cMaxPerGraph = self.getIntParam(self.ksParamGraphWizMaxPerGraph, iMin = 1, iMax = 24, iDefault = 8);
1027 fXkcdStyle = self.getBoolParam(self.ksParamGraphWizXkcdStyle, fDefault = False);
1028 fTabular = self.getBoolParam(self.ksParamGraphWizTabular, fDefault = False);
1029 idSrcTestSet = self.getIntParam(self.ksParamGraphWizSrcTestSetId, iDefault = None);
1030 self._checkForUnknownParameters();
1031
1032 dParams = \
1033 {
1034 self.ksParamEffectiveDate: tsEffective,
1035 self.ksParamReportPeriods: cPeriods,
1036 self.ksParamReportPeriodInHours: cHoursPerPeriod,
1037 self.ksParamReportSubject: sSubject,
1038 self.ksParamReportSubjectIds: asSubjectIds,
1039 self.ksParamGraphWizTestBoxIds: aidTestBoxes,
1040 self.ksParamGraphWizBuildCatIds: aidBuildCats,
1041 self.ksParamGraphWizTestCaseIds: aidTestCases,
1042 self.ksParamGraphWizSepTestVars: fSepTestVars,
1043
1044 self.ksParamGraphWizImpl: enmGraphImpl,
1045 self.ksParamGraphWizWidth: cx,
1046 self.ksParamGraphWizHeight: cy,
1047 self.ksParamGraphWizDpi: cDotsPerInch,
1048 self.ksParamGraphWizFontSize: cPtFont,
1049 self.ksParamGraphWizErrorBarY: fErrorBarY,
1050 self.ksParamGraphWizMaxErrorBarY: cMaxErrorBarY,
1051 self.ksParamGraphWizMaxPerGraph: cMaxPerGraph,
1052 self.ksParamGraphWizXkcdStyle: fXkcdStyle,
1053 self.ksParamGraphWizTabular: fTabular,
1054 self.ksParamGraphWizSrcTestSetId: idSrcTestSet,
1055 };
1056
1057 oModel = ReportGraphModel(self._oDb, tsEffective, cPeriods, cHoursPerPeriod, sSubject, asSubjectIds,
1058 aidTestBoxes, aidBuildCats, aidTestCases, fSepTestVars);
1059 oContent = WuiGraphWiz(oModel, dParams, fSubReport = False, fnDPrint = self._oSrvGlue.dprint, oDisp = self);
1060 (self._sPageTitle, self._sPageBody) = oContent.show();
1061 return True;
1062
1063 def _actionVcsHistoryTooltip(self):
1064 """
1065 Version control system history.
1066 """
1067 self._sTemplate = 'template-tooltip.html';
1068 from testmanager.webui.wuivcshistory import WuiVcsHistoryTooltip;
1069
1070 iRevision = self.getIntParam(self.ksParamVcsHistoryRevision, iMin = 0, iMax = 999999999);
1071 sRepository = self.getStringParam(self.ksParamVcsHistoryRepository);
1072 cEntries = self.getIntParam(self.ksParamVcsHistoryEntries, iMin = 1, iMax = 1024, iDefault = 8);
1073 self._checkForUnknownParameters();
1074
1075 aoEntries = VcsRevisionLogic(self._oDb).fetchTimeline(sRepository, iRevision, cEntries);
1076 oContent = WuiVcsHistoryTooltip(aoEntries, sRepository, iRevision, cEntries,
1077 fnDPrint = self._oSrvGlue.dprint, oDisp = self);
1078 (self._sPageTitle, self._sPageBody) = oContent.show();
1079 return True;
1080
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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