VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuitestresult.py@ 78352

Last change on this file since 78352 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuitestresult.py 76553 2019-01-01 01:45:53Z vboxsync $
3
4"""
5Test Manager WUI - Test Results.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2019 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: 76553 $"
30
31# Python imports.
32import datetime;
33
34# Validation Kit imports.
35from testmanager.webui.wuicontentbase import WuiContentBase, WuiListContentBase, WuiHtmlBase, WuiTmLink, WuiLinkBase, \
36 WuiSvnLink, WuiSvnLinkWithTooltip, WuiBuildLogLink, WuiRawHtml, \
37 WuiHtmlKeeper;
38from testmanager.webui.wuimain import WuiMain;
39from testmanager.webui.wuihlpform import WuiHlpForm;
40from testmanager.webui.wuiadminfailurereason import WuiFailureReasonAddLink, WuiFailureReasonDetailsLink;
41from testmanager.webui.wuitestresultfailure import WuiTestResultFailureDetailsLink;
42from testmanager.core.failurereason import FailureReasonData, FailureReasonLogic;
43from testmanager.core.report import ReportGraphModel, ReportModelBase;
44from testmanager.core.testbox import TestBoxData;
45from testmanager.core.testcase import TestCaseData;
46from testmanager.core.testset import TestSetData;
47from testmanager.core.testgroup import TestGroupData;
48from testmanager.core.testresultfailures import TestResultFailureData;
49from testmanager.core.build import BuildData;
50from testmanager.core import db;
51from testmanager import config;
52from common import webutils, utils;
53
54
55class WuiTestSetLink(WuiTmLink):
56 """ Test set link. """
57
58 def __init__(self, idTestSet, sName = WuiContentBase.ksShortDetailsLink, fBracketed = False):
59 WuiTmLink.__init__(self, sName, WuiMain.ksScriptName,
60 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
61 TestSetData.ksParam_idTestSet: idTestSet, }, fBracketed = fBracketed);
62 self.idTestSet = idTestSet;
63
64
65
66class WuiTestResult(WuiContentBase):
67 """Display test case result"""
68
69 def __init__(self, fnDPrint = None, oDisp = None):
70 WuiContentBase.__init__(self, fnDPrint = fnDPrint, oDisp = oDisp);
71
72 # Cyclic import hacks.
73 from testmanager.webui.wuiadmin import WuiAdmin;
74 self.oWuiAdmin = WuiAdmin;
75
76 def _toHtml(self, oObject):
77 """Translate some object to HTML."""
78 if isinstance(oObject, WuiHtmlBase):
79 return oObject.toHtml();
80 if db.isDbTimestamp(oObject):
81 return webutils.escapeElem(self.formatTsShort(oObject));
82 if db.isDbInterval(oObject):
83 return webutils.escapeElem(self.formatIntervalShort(oObject));
84 if utils.isString(oObject):
85 return webutils.escapeElem(oObject);
86 return webutils.escapeElem(str(oObject));
87
88 def _htmlTable(self, aoTableContent):
89 """Generate HTML code for table"""
90 sHtml = u' <table class="tmtbl-testresult-details" width="100%%">\n';
91
92 for aoSubRows in aoTableContent:
93 if not aoSubRows:
94 continue; # Can happen if there is no testsuit.
95 oCaption = aoSubRows[0];
96 sHtml += u' \n' \
97 u' <tr class="tmtbl-result-details-caption">\n' \
98 u' <td colspan="2">%s</td>\n' \
99 u' </tr>\n' \
100 % (self._toHtml(oCaption),);
101
102 iRow = 0;
103 for aoRow in aoSubRows[1:]:
104 iRow += 1;
105 sHtml += u' <tr class="%s">\n' % ('tmodd' if iRow & 1 else 'tmeven',);
106 if len(aoRow) == 1:
107 sHtml += u' <td class="tmtbl-result-details-subcaption" colspan="2">%s</td>\n' \
108 % (self._toHtml(aoRow[0]),);
109 else:
110 sHtml += u' <th scope="row">%s</th>\n' % (webutils.escapeElem(aoRow[0]),);
111 if len(aoRow) > 2:
112 sHtml += u' <td>%s</td>\n' % (aoRow[2](aoRow[1]),);
113 else:
114 sHtml += u' <td>%s</td>\n' % (self._toHtml(aoRow[1]),);
115 sHtml += u' </tr>\n';
116
117 sHtml += u' </table>\n';
118
119 return sHtml
120
121 def _highlightStatus(self, sStatus):
122 """Return sStatus string surrounded by HTML highlight code """
123 sTmp = '<font color=%s><b>%s</b></font>' \
124 % ('red' if sStatus == 'failure' else 'green', webutils.escapeElem(sStatus.upper()))
125 return sTmp
126
127 def _anchorAndAppendBinaries(self, sBinaries, aoRows):
128 """ Formats each binary (if any) into a row with a download link. """
129 if sBinaries is not None:
130 for sBinary in sBinaries.split(','):
131 if not webutils.hasSchema(sBinary):
132 sBinary = config.g_ksBuildBinUrlPrefix + sBinary;
133 aoRows.append([WuiLinkBase(webutils.getFilename(sBinary), sBinary, fBracketed = False),]);
134 return aoRows;
135
136
137 def _formatEventTimestampHtml(self, tsEvent, tsLog, idEvent, oTestSet):
138 """ Formats an event timestamp with a main log link. """
139 tsEvent = db.dbTimestampToZuluDatetime(tsEvent);
140 #sFormattedTimestamp = u'%04u\u2011%02u\u2011%02u\u00a0%02u:%02u:%02uZ' \
141 # % ( tsEvent.year, tsEvent.month, tsEvent.day,
142 # tsEvent.hour, tsEvent.minute, tsEvent.second,);
143 sFormattedTimestamp = u'%02u:%02u:%02uZ' \
144 % ( tsEvent.hour, tsEvent.minute, tsEvent.second,);
145 sTitle = u'#%u - %04u\u2011%02u\u2011%02u\u00a0%02u:%02u:%02u.%06uZ' \
146 % ( idEvent, tsEvent.year, tsEvent.month, tsEvent.day,
147 tsEvent.hour, tsEvent.minute, tsEvent.second, tsEvent.microsecond, );
148 tsLog = db.dbTimestampToZuluDatetime(tsLog);
149 sFragment = u'%02u_%02u_%02u_%06u' % ( tsLog.hour, tsLog.minute, tsLog.second, tsLog.microsecond);
150 return WuiTmLink(sFormattedTimestamp, '',
151 { WuiMain.ksParamAction: WuiMain.ksActionViewLog,
152 WuiMain.ksParamLogSetId: oTestSet.idTestSet, },
153 sFragmentId = sFragment, sTitle = sTitle, fBracketed = False, ).toHtml();
154
155 def _recursivelyGenerateEvents(self, oTestResult, sParentName, sLineage, iRow,
156 iFailure, oTestSet, iDepth): # pylint: disable=R0914
157 """
158 Recursively generate event table rows for the result set.
159
160 oTestResult is an object of the type TestResultDataEx.
161 """
162 # Hack: Replace empty outer test result name with (pretty) command line.
163 if iRow == 1:
164 sName = '';
165 sDisplayName = sParentName;
166 else:
167 sName = oTestResult.sName if sParentName == '' else '%s, %s' % (sParentName, oTestResult.sName,);
168 sDisplayName = webutils.escapeElem(sName);
169
170 # Format error count.
171 sErrCnt = '';
172 if oTestResult.cErrors > 0:
173 sErrCnt = ' (1 error)' if oTestResult.cErrors == 1 else ' (%d errors)' % oTestResult.cErrors;
174
175 # Format bits for adding or editing the failure reason. Level 0 is handled at the top of the page.
176 sChangeReason = '';
177 if oTestResult.cErrors > 0 and iDepth > 0 and self._oDisp is not None and not self._oDisp.isReadOnlyUser():
178 dTmp = {
179 self._oDisp.ksParamAction: self._oDisp.ksActionTestResultFailureAdd if oTestResult.oReason is None else
180 self._oDisp.ksActionTestResultFailureEdit,
181 TestResultFailureData.ksParam_idTestResult: oTestResult.idTestResult,
182 };
183 sChangeReason = ' <a href="?%s" class="tmtbl-edit-reason" onclick="addRedirectToAnchorHref(this)">%s</a> ' \
184 % ( webutils.encodeUrlParams(dTmp), WuiContentBase.ksShortEditLinkHtml );
185
186 # Format the include in graph checkboxes.
187 sLineage += ':%u' % (oTestResult.idStrName,);
188 sResultGraph = '<input type="checkbox" name="%s" value="%s%s" title="Include result in graph."/>' \
189 % (WuiMain.ksParamReportSubjectIds, ReportGraphModel.ksTypeResult, sLineage,);
190 sElapsedGraph = '';
191 if oTestResult.tsElapsed is not None:
192 sElapsedGraph = '<input type="checkbox" name="%s" value="%s%s" title="Include elapsed time in graph."/>' \
193 % ( WuiMain.ksParamReportSubjectIds, ReportGraphModel.ksTypeElapsed, sLineage);
194
195
196 if not oTestResult.aoChildren \
197 and len(oTestResult.aoValues) + len(oTestResult.aoMsgs) + len(oTestResult.aoFiles) == 0:
198 # Leaf - single row.
199 tsEvent = oTestResult.tsCreated;
200 if oTestResult.tsElapsed is not None:
201 tsEvent += oTestResult.tsElapsed;
202 sHtml = ' <tr class="%s tmtbl-events-leaf tmtbl-events-lvl%s tmstatusrow-%s" id="S%u">\n' \
203 ' <td id="E%u">%s</td>\n' \
204 ' <td>%s</td>\n' \
205 ' <td>%s</td>\n' \
206 ' <td>%s</td>\n' \
207 ' <td colspan="2"%s>%s%s%s</td>\n' \
208 ' <td>%s</td>\n' \
209 ' </tr>\n' \
210 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth, oTestResult.enmStatus, oTestResult.idTestResult,
211 oTestResult.idTestResult,
212 self._formatEventTimestampHtml(tsEvent, oTestResult.tsCreated, oTestResult.idTestResult, oTestSet),
213 sElapsedGraph,
214 webutils.escapeElem(self.formatIntervalShort(oTestResult.tsElapsed)) if oTestResult.tsElapsed is not None
215 else '',
216 sDisplayName,
217 ' id="failure-%u"' % (iFailure,) if oTestResult.isFailure() else '',
218 webutils.escapeElem(oTestResult.enmStatus), webutils.escapeElem(sErrCnt),
219 sChangeReason if oTestResult.oReason is None else '',
220 sResultGraph );
221 iRow += 1;
222 else:
223 # Multiple rows.
224 sHtml = ' <tr class="%s tmtbl-events-first tmtbl-events-lvl%s ">\n' \
225 ' <td>%s</td>\n' \
226 ' <td></td>\n' \
227 ' <td></td>\n' \
228 ' <td>%s</td>\n' \
229 ' <td colspan="2">%s</td>\n' \
230 ' <td></td>\n' \
231 ' </tr>\n' \
232 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth,
233 self._formatEventTimestampHtml(oTestResult.tsCreated, oTestResult.tsCreated,
234 oTestResult.idTestResult, oTestSet),
235 sDisplayName,
236 'running' if oTestResult.tsElapsed is None else '', );
237 iRow += 1;
238
239 # Depth. Check if our error count is just reflecting the one of our children.
240 cErrorsBelow = 0;
241 for oChild in oTestResult.aoChildren:
242 (sChildHtml, iRow, iFailure) = self._recursivelyGenerateEvents(oChild, sName, sLineage,
243 iRow, iFailure, oTestSet, iDepth + 1);
244 sHtml += sChildHtml;
245 cErrorsBelow += oChild.cErrors;
246
247 # Messages.
248 for oMsg in oTestResult.aoMsgs:
249 sHtml += ' <tr class="%s tmtbl-events-message tmtbl-events-lvl%s">\n' \
250 ' <td>%s</td>\n' \
251 ' <td></td>\n' \
252 ' <td></td>\n' \
253 ' <td colspan="3">%s: %s</td>\n' \
254 ' <td></td>\n' \
255 ' </tr>\n' \
256 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth,
257 self._formatEventTimestampHtml(oMsg.tsCreated, oMsg.tsCreated, oMsg.idTestResultMsg, oTestSet),
258 webutils.escapeElem(oMsg.enmLevel),
259 webutils.escapeElem(oMsg.sMsg), );
260 iRow += 1;
261
262 # Values.
263 for oValue in oTestResult.aoValues:
264 sHtml += ' <tr class="%s tmtbl-events-value tmtbl-events-lvl%s">\n' \
265 ' <td>%s</td>\n' \
266 ' <td></td>\n' \
267 ' <td></td>\n' \
268 ' <td>%s</td>\n' \
269 ' <td class="tmtbl-events-number">%s</td>\n' \
270 ' <td class="tmtbl-events-unit">%s</td>\n' \
271 ' <td><input type="checkbox" name="%s" value="%s%s:%u" title="Include value in graph."></td>\n' \
272 ' </tr>\n' \
273 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth,
274 self._formatEventTimestampHtml(oValue.tsCreated, oValue.tsCreated, oValue.idTestResultValue, oTestSet),
275 webutils.escapeElem(oValue.sName),
276 utils.formatNumber(oValue.lValue).replace(' ', '&nbsp;'),
277 webutils.escapeElem(oValue.sUnit),
278 WuiMain.ksParamReportSubjectIds, ReportGraphModel.ksTypeValue, sLineage, oValue.idStrName, );
279 iRow += 1;
280
281 # Files.
282 for oFile in oTestResult.aoFiles:
283 if oFile.sMime in [ 'text/plain', ]:
284 aoLinks = [
285 WuiTmLink('%s (%s)' % (oFile.sFile, oFile.sKind), '',
286 { self._oDisp.ksParamAction: self._oDisp.ksActionViewLog,
287 self._oDisp.ksParamLogSetId: oTestSet.idTestSet,
288 self._oDisp.ksParamLogFileId: oFile.idTestResultFile, },
289 sTitle = oFile.sDescription),
290 WuiTmLink('View Raw', '',
291 { self._oDisp.ksParamAction: self._oDisp.ksActionGetFile,
292 self._oDisp.ksParamGetFileSetId: oTestSet.idTestSet,
293 self._oDisp.ksParamGetFileId: oFile.idTestResultFile,
294 self._oDisp.ksParamGetFileDownloadIt: False, },
295 sTitle = oFile.sDescription),
296 ]
297 else:
298 aoLinks = [
299 WuiTmLink('%s (%s)' % (oFile.sFile, oFile.sKind), '',
300 { self._oDisp.ksParamAction: self._oDisp.ksActionGetFile,
301 self._oDisp.ksParamGetFileSetId: oTestSet.idTestSet,
302 self._oDisp.ksParamGetFileId: oFile.idTestResultFile,
303 self._oDisp.ksParamGetFileDownloadIt: False, },
304 sTitle = oFile.sDescription),
305 ]
306 aoLinks.append(WuiTmLink('Download', '',
307 { self._oDisp.ksParamAction: self._oDisp.ksActionGetFile,
308 self._oDisp.ksParamGetFileSetId: oTestSet.idTestSet,
309 self._oDisp.ksParamGetFileId: oFile.idTestResultFile,
310 self._oDisp.ksParamGetFileDownloadIt: True, },
311 sTitle = oFile.sDescription));
312
313 sHtml += ' <tr class="%s tmtbl-events-file tmtbl-events-lvl%s">\n' \
314 ' <td>%s</td>\n' \
315 ' <td></td>\n' \
316 ' <td></td>\n' \
317 ' <td>%s</td>\n' \
318 ' <td></td>\n' \
319 ' <td></td>\n' \
320 ' <td></td>\n' \
321 ' </tr>\n' \
322 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth,
323 self._formatEventTimestampHtml(oFile.tsCreated, oFile.tsCreated, oFile.idTestResultFile, oTestSet),
324 '\n'.join(oLink.toHtml() for oLink in aoLinks),);
325 iRow += 1;
326
327 # Done?
328 if oTestResult.tsElapsed is not None:
329 tsEvent = oTestResult.tsCreated + oTestResult.tsElapsed;
330 sHtml += ' <tr class="%s tmtbl-events-final tmtbl-events-lvl%s tmstatusrow-%s" id="E%d">\n' \
331 ' <td>%s</td>\n' \
332 ' <td>%s</td>\n' \
333 ' <td>%s</td>\n' \
334 ' <td>%s</td>\n' \
335 ' <td colspan="2"%s>%s%s%s</td>\n' \
336 ' <td>%s</td>\n' \
337 ' </tr>\n' \
338 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth, oTestResult.enmStatus, oTestResult.idTestResult,
339 self._formatEventTimestampHtml(tsEvent, tsEvent, oTestResult.idTestResult, oTestSet),
340 sElapsedGraph,
341 webutils.escapeElem(self.formatIntervalShort(oTestResult.tsElapsed)),
342 sDisplayName,
343 ' id="failure-%u"' % (iFailure,) if oTestResult.isFailure() else '',
344 webutils.escapeElem(oTestResult.enmStatus), webutils.escapeElem(sErrCnt),
345 sChangeReason if cErrorsBelow < oTestResult.cErrors and oTestResult.oReason is None else '',
346 sResultGraph);
347 iRow += 1;
348
349 # Failure reason.
350 if oTestResult.oReason is not None:
351 sReasonText = '%s / %s' % ( oTestResult.oReason.oFailureReason.oCategory.sShort,
352 oTestResult.oReason.oFailureReason.sShort, );
353 sCommentHtml = '';
354 if oTestResult.oReason.sComment and oTestResult.oReason.sComment.strip():
355 sCommentHtml = '<br>' + webutils.escapeElem(oTestResult.oReason.sComment.strip());
356 sCommentHtml = sCommentHtml.replace('\n', '<br>');
357
358 sDetailedReason = ' <a href="?%s" class="tmtbl-show-reason">%s</a>' \
359 % ( webutils.encodeUrlParams({ self._oDisp.ksParamAction:
360 self._oDisp.ksActionTestResultFailureDetails,
361 TestResultFailureData.ksParam_idTestResult:
362 oTestResult.idTestResult,}),
363 WuiContentBase.ksShortDetailsLinkHtml,);
364
365 sHtml += ' <tr class="%s tmtbl-events-reason tmtbl-events-lvl%s">\n' \
366 ' <td>%s</td>\n' \
367 ' <td colspan="2">%s</td>\n' \
368 ' <td colspan="3">%s%s%s%s</td>\n' \
369 ' <td>%s</td>\n' \
370 ' </tr>\n' \
371 % ( 'tmodd' if iRow & 1 else 'tmeven', iDepth,
372 webutils.escapeElem(self.formatTsShort(oTestResult.oReason.tsEffective)),
373 oTestResult.oReason.oAuthor.sUsername,
374 webutils.escapeElem(sReasonText), sDetailedReason, sChangeReason,
375 sCommentHtml,
376 'todo');
377 iRow += 1;
378
379 if oTestResult.isFailure():
380 iFailure += 1;
381
382 return (sHtml, iRow, iFailure);
383
384
385 def _generateMainReason(self, oTestResultTree, oTestSet):
386 """
387 Generates the form for displaying and updating the main failure reason.
388
389 oTestResultTree is an instance TestResultDataEx.
390 oTestSet is an instance of TestSetData.
391
392 """
393 _ = oTestSet;
394 sHtml = ' ';
395
396 if oTestResultTree.isFailure() or oTestResultTree.cErrors > 0:
397 sHtml += ' <h2>Failure Reason:</h2>\n';
398 oData = oTestResultTree.oReason;
399
400 # We need the failure reasons for the combobox.
401 aoFailureReasons = FailureReasonLogic(self._oDisp.getDb()).fetchForCombo('Test Sheriff, you figure out why!');
402 assert aoFailureReasons;
403
404 # For now we'll use the standard form helper.
405 sFormActionUrl = '%s?%s=%s' % ( self._oDisp.ksScriptName, self._oDisp.ksParamAction,
406 WuiMain.ksActionTestResultFailureAddPost if oData is None else
407 WuiMain.ksActionTestResultFailureEditPost )
408 fReadOnly = not self._oDisp or self._oDisp.isReadOnlyUser();
409 oForm = WuiHlpForm('failure-reason', sFormActionUrl,
410 sOnSubmit = WuiHlpForm.ksOnSubmit_AddReturnToFieldWithCurrentUrl, fReadOnly = fReadOnly);
411 oForm.addTextHidden(TestResultFailureData.ksParam_idTestResult, oTestResultTree.idTestResult);
412 oForm.addTextHidden(TestResultFailureData.ksParam_idTestSet, oTestSet.idTestSet);
413 if oData is not None:
414 oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, oData.idFailureReason, 'Reason',
415 aoFailureReasons,
416 sPostHtml = u' ' + WuiFailureReasonDetailsLink(oData.idFailureReason).toHtml()
417 + (u' ' + WuiFailureReasonAddLink('New', fBracketed = False).toHtml()
418 if not fReadOnly else u''));
419 oForm.addMultilineText(TestResultFailureData.ksParam_sComment, oData.sComment, 'Comment')
420
421 oForm.addNonText(u'%s (%s), %s'
422 % ( oData.oAuthor.sUsername, oData.oAuthor.sUsername,
423 self.formatTsShort(oData.tsEffective),),
424 'Sheriff',
425 sPostHtml = ' ' + WuiTestResultFailureDetailsLink(oData.idTestResult, "Show Details").toHtml() )
426
427 oForm.addTextHidden(TestResultFailureData.ksParam_tsEffective, oData.tsEffective);
428 oForm.addTextHidden(TestResultFailureData.ksParam_tsExpire, oData.tsExpire);
429 oForm.addTextHidden(TestResultFailureData.ksParam_uidAuthor, oData.uidAuthor);
430 oForm.addSubmit('Change Reason');
431 else:
432 oForm.addComboBox(TestResultFailureData.ksParam_idFailureReason, -1, 'Reason', aoFailureReasons,
433 sPostHtml = ' ' + WuiFailureReasonAddLink('New').toHtml() if not fReadOnly else '');
434 oForm.addMultilineText(TestResultFailureData.ksParam_sComment, '', 'Comment');
435 oForm.addTextHidden(TestResultFailureData.ksParam_tsEffective, '');
436 oForm.addTextHidden(TestResultFailureData.ksParam_tsExpire, '');
437 oForm.addTextHidden(TestResultFailureData.ksParam_uidAuthor, '');
438 oForm.addSubmit('Add Reason');
439
440 sHtml += oForm.finalize();
441 return sHtml;
442
443
444 def showTestCaseResultDetails(self, # pylint: disable=R0914,R0915
445 oTestResultTree,
446 oTestSet,
447 oBuildEx,
448 oValidationKitEx,
449 oTestBox,
450 oTestGroup,
451 oTestCaseEx,
452 oTestVarEx):
453 """Show detailed result"""
454 def getTcDepsHtmlList(aoTestCaseData):
455 """Get HTML <ul> list of Test Case name items"""
456 if aoTestCaseData:
457 sTmp = '<ul>'
458 for oTestCaseData in aoTestCaseData:
459 sTmp += '<li>%s</li>' % (webutils.escapeElem(oTestCaseData.sName),);
460 sTmp += '</ul>'
461 else:
462 sTmp = 'No items'
463 return sTmp
464
465 def getGrDepsHtmlList(aoGlobalResourceData):
466 """Get HTML <ul> list of Global Resource name items"""
467 if aoGlobalResourceData:
468 sTmp = '<ul>'
469 for oGlobalResourceData in aoGlobalResourceData:
470 sTmp += '<li>%s</li>' % (webutils.escapeElem(oGlobalResourceData.sName),);
471 sTmp += '</ul>'
472 else:
473 sTmp = 'No items'
474 return sTmp
475
476
477 asHtml = []
478
479 from testmanager.webui.wuireport import WuiReportSummaryLink;
480 tsReportEffectiveDate = None;
481 if oTestSet.tsDone is not None:
482 tsReportEffectiveDate = oTestSet.tsDone + datetime.timedelta(days = 4);
483 if tsReportEffectiveDate >= self.getNowTs():
484 tsReportEffectiveDate = None;
485
486 # Test result + test set details.
487 aoResultRows = [
488 WuiHtmlKeeper([ WuiTmLink(oTestCaseEx.sName, self.oWuiAdmin.ksScriptName,
489 { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestCaseDetails,
490 TestCaseData.ksParam_idTestCase: oTestCaseEx.idTestCase,
491 self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsConfig, },
492 fBracketed = False),
493 WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oTestCaseEx.idTestCase,
494 tsNow = tsReportEffectiveDate, fBracketed = False),
495 ]),
496 ];
497 if oTestCaseEx.sDescription:
498 aoResultRows.append([oTestCaseEx.sDescription,]);
499 aoResultRows.append([ 'Status:', WuiRawHtml('<span class="tmspan-status-%s">%s</span>'
500 % (oTestResultTree.enmStatus, oTestResultTree.enmStatus,))]);
501 if oTestResultTree.cErrors > 0:
502 aoResultRows.append(( 'Errors:', oTestResultTree.cErrors ));
503 aoResultRows.append([ 'Elapsed:', oTestResultTree.tsElapsed ]);
504 cSecCfgTimeout = oTestCaseEx.cSecTimeout if oTestVarEx.cSecTimeout is None else oTestVarEx.cSecTimeout;
505 cSecEffTimeout = cSecCfgTimeout * oTestBox.pctScaleTimeout / 100;
506 aoResultRows.append([ 'Timeout:',
507 '%s (%s sec)' % (utils.formatIntervalSeconds(cSecEffTimeout), cSecEffTimeout,) ]);
508 if cSecEffTimeout != cSecCfgTimeout:
509 aoResultRows.append([ 'Cfg Timeout:',
510 '%s (%s sec)' % (utils.formatIntervalSeconds(cSecCfgTimeout), cSecCfgTimeout,) ]);
511 aoResultRows += [
512 ( 'Started:', WuiTmLink(self.formatTsShort(oTestSet.tsCreated), WuiMain.ksScriptName,
513 { WuiMain.ksParamAction: WuiMain.ksActionResultsUnGrouped,
514 WuiMain.ksParamEffectiveDate: oTestSet.tsCreated, },
515 fBracketed = False) ),
516 ];
517 if oTestSet.tsDone is not None:
518 aoResultRows += [ ( 'Done:',
519 WuiTmLink(self.formatTsShort(oTestSet.tsDone), WuiMain.ksScriptName,
520 { WuiMain.ksParamAction: WuiMain.ksActionResultsUnGrouped,
521 WuiMain.ksParamEffectiveDate: oTestSet.tsDone, },
522 fBracketed = False) ) ];
523 else:
524 aoResultRows += [( 'Done:', 'Still running...')];
525 aoResultRows += [( 'Config:', oTestSet.tsConfig )];
526 if oTestVarEx.cGangMembers > 1:
527 aoResultRows.append([ 'Member No:', '#%s (of %s)' % (oTestSet.iGangMemberNo, oTestVarEx.cGangMembers) ]);
528
529 aoResultRows += [
530 ( 'Test Group:',
531 WuiHtmlKeeper([ WuiTmLink(oTestGroup.sName, self.oWuiAdmin.ksScriptName,
532 { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestGroupDetails,
533 TestGroupData.ksParam_idTestGroup: oTestGroup.idTestGroup,
534 self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsConfig, },
535 fBracketed = False),
536 WuiReportSummaryLink(ReportModelBase.ksSubTestGroup, oTestGroup.idTestGroup,
537 tsNow = tsReportEffectiveDate, fBracketed = False),
538 ]), ),
539 ];
540 if oTestVarEx.sTestBoxReqExpr is not None:
541 aoResultRows.append([ 'TestBox reqs:', oTestVarEx.sTestBoxReqExpr ]);
542 elif oTestCaseEx.sTestBoxReqExpr is not None or oTestVarEx.sTestBoxReqExpr is not None:
543 aoResultRows.append([ 'TestBox reqs:', oTestCaseEx.sTestBoxReqExpr ]);
544 if oTestVarEx.sBuildReqExpr is not None:
545 aoResultRows.append([ 'Build reqs:', oTestVarEx.sBuildReqExpr ]);
546 elif oTestCaseEx.sBuildReqExpr is not None or oTestVarEx.sBuildReqExpr is not None:
547 aoResultRows.append([ 'Build reqs:', oTestCaseEx.sBuildReqExpr ]);
548 if oTestCaseEx.sValidationKitZips is not None and oTestCaseEx.sValidationKitZips != '@VALIDATIONKIT_ZIP@':
549 aoResultRows.append([ 'Validation Kit:', oTestCaseEx.sValidationKitZips ]);
550 if oTestCaseEx.aoDepTestCases:
551 aoResultRows.append([ 'Prereq. Test Cases:', oTestCaseEx.aoDepTestCases, getTcDepsHtmlList ]);
552 if oTestCaseEx.aoDepGlobalResources:
553 aoResultRows.append([ 'Global Resources:', oTestCaseEx.aoDepGlobalResources, getGrDepsHtmlList ]);
554
555 # Builds.
556 aoBuildRows = [];
557 if oBuildEx is not None:
558 aoBuildRows += [
559 WuiHtmlKeeper([ WuiTmLink('Build', self.oWuiAdmin.ksScriptName,
560 { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionBuildDetails,
561 BuildData.ksParam_idBuild: oBuildEx.idBuild,
562 self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsCreated, },
563 fBracketed = False),
564 WuiReportSummaryLink(ReportModelBase.ksSubBuild, oBuildEx.idBuild,
565 tsNow = tsReportEffectiveDate, fBracketed = False), ]),
566 ];
567 self._anchorAndAppendBinaries(oBuildEx.sBinaries, aoBuildRows);
568 aoBuildRows += [
569 ( 'Revision:', WuiSvnLinkWithTooltip(oBuildEx.iRevision, oBuildEx.oCat.sRepository,
570 fBracketed = False) ),
571 ( 'Product:', oBuildEx.oCat.sProduct ),
572 ( 'Branch:', oBuildEx.oCat.sBranch ),
573 ( 'Type:', oBuildEx.oCat.sType ),
574 ( 'Version:', oBuildEx.sVersion ),
575 ( 'Created:', oBuildEx.tsCreated ),
576 ];
577 if oBuildEx.uidAuthor is not None:
578 aoBuildRows += [ ( 'Author ID:', oBuildEx.uidAuthor ), ];
579 if oBuildEx.sLogUrl is not None:
580 aoBuildRows += [ ( 'Log:', WuiBuildLogLink(oBuildEx.sLogUrl, fBracketed = False) ), ];
581
582 aoValidationKitRows = [];
583 if oValidationKitEx is not None:
584 aoValidationKitRows += [
585 WuiTmLink('Validation Kit', self.oWuiAdmin.ksScriptName,
586 { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionBuildDetails,
587 BuildData.ksParam_idBuild: oValidationKitEx.idBuild,
588 self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsCreated, },
589 fBracketed = False),
590 ];
591 self._anchorAndAppendBinaries(oValidationKitEx.sBinaries, aoValidationKitRows);
592 aoValidationKitRows += [ ( 'Revision:', WuiSvnLink(oValidationKitEx.iRevision, fBracketed = False) ) ];
593 if oValidationKitEx.oCat.sProduct != 'VBox TestSuite':
594 aoValidationKitRows += [ ( 'Product:', oValidationKitEx.oCat.sProduct ), ];
595 if oValidationKitEx.oCat.sBranch != 'trunk':
596 aoValidationKitRows += [ ( 'Product:', oValidationKitEx.oCat.sBranch ), ];
597 if oValidationKitEx.oCat.sType != 'release':
598 aoValidationKitRows += [ ( 'Type:', oValidationKitEx.oCat.sType), ];
599 if oValidationKitEx.sVersion != '0.0.0':
600 aoValidationKitRows += [ ( 'Version:', oValidationKitEx.sVersion ), ];
601 aoValidationKitRows += [
602 ( 'Created:', oValidationKitEx.tsCreated ),
603 ];
604 if oValidationKitEx.uidAuthor is not None:
605 aoValidationKitRows += [ ( 'Author ID:', oValidationKitEx.uidAuthor ), ];
606 if oValidationKitEx.sLogUrl is not None:
607 aoValidationKitRows += [ ( 'Log:', WuiBuildLogLink(oValidationKitEx.sLogUrl, fBracketed = False) ), ];
608
609 # TestBox.
610 aoTestBoxRows = [
611 WuiHtmlKeeper([ WuiTmLink(oTestBox.sName, self.oWuiAdmin.ksScriptName,
612 { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestBoxDetails,
613 TestBoxData.ksParam_idGenTestBox: oTestSet.idGenTestBox, },
614 fBracketed = False),
615 WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestSet.idTestBox,
616 tsNow = tsReportEffectiveDate, fBracketed = False), ]),
617 ];
618 if oTestBox.sDescription:
619 aoTestBoxRows.append([oTestBox.sDescription, ]);
620 aoTestBoxRows += [
621 ( 'IP:', oTestBox.ip ),
622 #( 'UUID:', oTestBox.uuidSystem ),
623 #( 'Enabled:', oTestBox.fEnabled ),
624 #( 'Lom Kind:', oTestBox.enmLomKind ),
625 #( 'Lom IP:', oTestBox.ipLom ),
626 ( 'OS/Arch:', '%s.%s' % (oTestBox.sOs, oTestBox.sCpuArch) ),
627 ( 'OS Version:', oTestBox.sOsVersion ),
628 ( 'CPUs:', oTestBox.cCpus ),
629 ];
630 if oTestBox.sCpuName is not None:
631 aoTestBoxRows.append(['CPU Name', oTestBox.sCpuName.replace(' ', ' ')]);
632 if oTestBox.lCpuRevision is not None:
633 sMarch = oTestBox.queryCpuMicroarch();
634 if sMarch is not None:
635 aoTestBoxRows.append( ('CPU Microarch', sMarch) );
636 uFamily = oTestBox.getCpuFamily();
637 uModel = oTestBox.getCpuModel();
638 uStepping = oTestBox.getCpuStepping();
639 aoTestBoxRows += [
640 ( 'CPU Family', '%u (%#x)' % ( uFamily, uFamily, ) ),
641 ( 'CPU Model', '%u (%#x)' % ( uModel, uModel, ) ),
642 ( 'CPU Stepping', '%u (%#x)' % ( uStepping, uStepping, ) ),
643 ];
644 asFeatures = [ oTestBox.sCpuVendor, ];
645 if oTestBox.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt');
646 if oTestBox.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
647 if oTestBox.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
648 if oTestBox.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
649 aoTestBoxRows += [
650 ( 'Features:', u' '.join(asFeatures) ),
651 ( 'RAM size:', '%s MB' % (oTestBox.cMbMemory,) ),
652 ( 'Scratch Size:', '%s MB' % (oTestBox.cMbScratch,) ),
653 ( 'Scale Timeout:', '%s%%' % (oTestBox.pctScaleTimeout,) ),
654 ( 'Script Rev:', WuiSvnLink(oTestBox.iTestBoxScriptRev, fBracketed = False) ),
655 ( 'Python:', oTestBox.formatPythonVersion() ),
656 ( 'Pending Command:', oTestBox.enmPendingCmd ),
657 ];
658
659 aoRows = [
660 aoResultRows,
661 aoBuildRows,
662 aoValidationKitRows,
663 aoTestBoxRows,
664 ];
665
666 asHtml.append(self._htmlTable(aoRows));
667
668 #
669 # Convert the tree to a list of events, values, message and files.
670 #
671 sHtmlEvents = '';
672 sHtmlEvents += '<table class="tmtbl-events" id="tmtbl-events" width="100%">\n';
673 sHtmlEvents += ' <tr class="tmheader">\n' \
674 ' <th>When</th>\n' \
675 ' <th></th>\n' \
676 ' <th>Elapsed</th>\n' \
677 ' <th>Event name</th>\n' \
678 ' <th colspan="2">Value (status)</th>' \
679 ' <th></th>\n' \
680 ' </tr>\n';
681 sPrettyCmdLine = '&nbsp;\\<br>&nbsp;&nbsp;&nbsp;&nbsp;\n'.join(webutils.escapeElem(oTestCaseEx.sBaseCmd
682 + ' '
683 + oTestVarEx.sArgs).split() );
684 (sTmp, _, cFailures) = self._recursivelyGenerateEvents(oTestResultTree, sPrettyCmdLine, '', 1, 0, oTestSet, 0);
685 sHtmlEvents += sTmp;
686
687 sHtmlEvents += '</table>\n'
688
689 #
690 # Put it all together.
691 #
692 sHtml = '<table class="tmtbl-testresult-details-base" width="100%">\n';
693 sHtml += ' <tr>\n'
694 sHtml += ' <td valign="top" width="20%%">\n%s\n</td>\n' % ' <br>\n'.join(asHtml);
695
696 sHtml += ' <td valign="top" width="80%" style="padding-left:6px">\n';
697 sHtml += self._generateMainReason(oTestResultTree, oTestSet);
698
699 sHtml += ' <h2>Events:</h2>\n';
700 sHtml += ' <form action="#" method="get" id="graph-form">\n' \
701 ' <input type="hidden" name="%s" value="%s"/>\n' \
702 ' <input type="hidden" name="%s" value="%u"/>\n' \
703 ' <input type="hidden" name="%s" value="%u"/>\n' \
704 ' <input type="hidden" name="%s" value="%u"/>\n' \
705 ' <input type="hidden" name="%s" value="%u"/>\n' \
706 % ( WuiMain.ksParamAction, WuiMain.ksActionGraphWiz,
707 WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox,
708 WuiMain.ksParamGraphWizBuildCatIds, oBuildEx.idBuildCategory,
709 WuiMain.ksParamGraphWizTestCaseIds, oTestSet.idTestCase,
710 WuiMain.ksParamGraphWizSrcTestSetId, oTestSet.idTestSet,
711 );
712 if oTestSet.tsDone is not None:
713 sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \
714 % ( WuiMain.ksParamEffectiveDate, oTestSet.tsDone, );
715 sHtml += ' <p>\n';
716 sFormButton = '<button type="submit" onclick="%s">Show graphs</button>' \
717 % ( webutils.escapeAttr('addDynamicGraphInputs("graph-form", "main", "%s", "%s");'
718 % (WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizDpi, )) );
719 sHtml += ' ' + sFormButton + '\n';
720 sHtml += ' %s %s %s\n' \
721 % ( WuiTmLink('Log File', '',
722 { WuiMain.ksParamAction: WuiMain.ksActionViewLog,
723 WuiMain.ksParamLogSetId: oTestSet.idTestSet,
724 }),
725 WuiTmLink('Raw Log', '',
726 { WuiMain.ksParamAction: WuiMain.ksActionGetFile,
727 WuiMain.ksParamGetFileSetId: oTestSet.idTestSet,
728 WuiMain.ksParamGetFileDownloadIt: False,
729 }),
730 WuiTmLink('Download Log', '',
731 { WuiMain.ksParamAction: WuiMain.ksActionGetFile,
732 WuiMain.ksParamGetFileSetId: oTestSet.idTestSet,
733 WuiMain.ksParamGetFileDownloadIt: True,
734 }),
735 );
736 sHtml += ' </p>\n';
737 if cFailures == 1:
738 sHtml += ' <p>%s</p>\n' % ( WuiTmLink('Jump to failure', '#failure-0'), )
739 elif cFailures > 1:
740 sHtml += ' <p>Jump to failure: ';
741 if cFailures <= 13:
742 for iFailure in range(0, cFailures):
743 sHtml += ' ' + WuiTmLink('#%u' % (iFailure,), '#failure-%u' % (iFailure,)).toHtml();
744 else:
745 for iFailure in range(0, 6):
746 sHtml += ' ' + WuiTmLink('#%u' % (iFailure,), '#failure-%u' % (iFailure,)).toHtml();
747 sHtml += ' ... ';
748 for iFailure in range(cFailures - 6, cFailures):
749 sHtml += ' ' + WuiTmLink('#%u' % (iFailure,), '#failure-%u' % (iFailure,)).toHtml();
750 sHtml += ' </p>\n';
751
752 sHtml += sHtmlEvents;
753 sHtml += ' <p>' + sFormButton + '</p>\n';
754 sHtml += ' </form>\n';
755 sHtml += ' </td>\n';
756
757 sHtml += ' </tr>\n';
758 sHtml += '</table>\n';
759
760 return ('Test Case result details', sHtml)
761
762
763class WuiGroupedResultList(WuiListContentBase):
764 """
765 WUI results content generator.
766 """
767
768 def __init__(self, aoEntries, cEntriesCount, iPage, cItemsPerPage, tsEffective, fnDPrint, oDisp,
769 aiSelectedSortColumns = None):
770 """Override initialization"""
771 WuiListContentBase.__init__(self, aoEntries, iPage, cItemsPerPage, tsEffective,
772 sTitle = 'Ungrouped (%d)' % cEntriesCount, sId = 'results',
773 fnDPrint = fnDPrint, oDisp = oDisp, aiSelectedSortColumns = aiSelectedSortColumns);
774
775 self._cEntriesCount = cEntriesCount
776
777 self._asColumnHeaders = [
778 'Start',
779 'Product Build',
780 'Kit',
781 'Box',
782 'OS.Arch',
783 'Test Case',
784 'Elapsed',
785 'Result',
786 'Reason',
787 ];
788 self._asColumnAttribs = ['align="center"', 'align="center"', 'align="center"',
789 'align="center"', 'align="center"', 'align="center"',
790 'align="center"', 'align="center"', 'align="center"',
791 'align="center"', 'align="center"', 'align="center"',
792 'align="center"', ];
793
794
795 # Prepare parameter lists.
796 self._dTestBoxLinkParams = self._oDisp.getParameters();
797 self._dTestBoxLinkParams[WuiMain.ksParamAction] = WuiMain.ksActionResultsGroupedByTestBox;
798
799 self._dTestCaseLinkParams = self._oDisp.getParameters();
800 self._dTestCaseLinkParams[WuiMain.ksParamAction] = WuiMain.ksActionResultsGroupedByTestCase;
801
802 self._dRevLinkParams = self._oDisp.getParameters();
803 self._dRevLinkParams[WuiMain.ksParamAction] = WuiMain.ksActionResultsGroupedByBuildRev;
804
805
806
807 def _formatListEntry(self, iEntry):
808 """
809 Format *show all* table entry
810 """
811 oEntry = self._aoEntries[iEntry];
812
813 from testmanager.webui.wuiadmin import WuiAdmin;
814 from testmanager.webui.wuireport import WuiReportSummaryLink;
815
816 oValidationKit = None;
817 if oEntry.idBuildTestSuite is not None:
818 oValidationKit = WuiTmLink('r%s' % (oEntry.iRevisionTestSuite,),
819 WuiAdmin.ksScriptName,
820 { WuiAdmin.ksParamAction: WuiAdmin.ksActionBuildDetails,
821 BuildData.ksParam_idBuild: oEntry.idBuildTestSuite },
822 fBracketed = False);
823
824 aoTestSetLinks = [];
825 aoTestSetLinks.append(WuiTmLink(oEntry.enmStatus,
826 WuiMain.ksScriptName,
827 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
828 TestSetData.ksParam_idTestSet: oEntry.idTestSet },
829 fBracketed = False));
830 if oEntry.cErrors > 0:
831 aoTestSetLinks.append(WuiRawHtml('-'));
832 aoTestSetLinks.append(WuiTmLink('%d error%s' % (oEntry.cErrors, '' if oEntry.cErrors == 1 else 's', ),
833 WuiMain.ksScriptName,
834 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails,
835 TestSetData.ksParam_idTestSet: oEntry.idTestSet },
836 sFragmentId = 'failure-0', fBracketed = False));
837
838
839 self._dTestBoxLinkParams[WuiMain.ksParamGroupMemberId] = oEntry.idTestBox;
840 self._dTestCaseLinkParams[WuiMain.ksParamGroupMemberId] = oEntry.idTestCase;
841 self._dRevLinkParams[WuiMain.ksParamGroupMemberId] = oEntry.iRevision;
842
843 sTestBoxTitle = u'';
844 if oEntry.sCpuVendor is not None:
845 sTestBoxTitle += 'CPU vendor:\t%s\n' % ( oEntry.sCpuVendor, );
846 if oEntry.sCpuName is not None:
847 sTestBoxTitle += 'CPU name:\t%s\n' % ( ' '.join(oEntry.sCpuName.split()), );
848 if oEntry.sOsVersion is not None:
849 sTestBoxTitle += 'OS version:\t%s\n' % ( oEntry.sOsVersion, );
850 asFeatures = [];
851 if oEntry.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt');
852 if oEntry.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging');
853 if oEntry.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest');
854 #if oEntry.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU');
855 sTestBoxTitle += u'CPU features:\t' + u', '.join(asFeatures);
856
857 # Testcase
858 if oEntry.sSubName:
859 sTestCaseName = '%s / %s' % (oEntry.sTestCaseName, oEntry.sSubName,);
860 else:
861 sTestCaseName = oEntry.sTestCaseName;
862
863 # Reason:
864 aoReasons = [];
865 for oIt in oEntry.aoFailureReasons:
866 sReasonTitle = 'Reason: \t%s\n' % ( oIt.oFailureReason.sShort, );
867 sReasonTitle += 'Category:\t%s\n' % ( oIt.oFailureReason.oCategory.sShort, );
868 sReasonTitle += 'Assigned:\t%s\n' % ( self.formatTsShort(oIt.tsFailureReasonAssigned), );
869 sReasonTitle += 'By User: \t%s\n' % ( oIt.oFailureReasonAssigner.sUsername, );
870 if oIt.sFailureReasonComment:
871 sReasonTitle += 'Comment: \t%s\n' % ( oIt.sFailureReasonComment, );
872 if oIt.oFailureReason.iTicket is not None and oIt.oFailureReason.iTicket > 0:
873 sReasonTitle += 'xTracker:\t#%s\n' % ( oIt.oFailureReason.iTicket, );
874 for i, sUrl in enumerate(oIt.oFailureReason.asUrls):
875 sUrl = sUrl.strip();
876 if sUrl:
877 sReasonTitle += 'URL#%u: \t%s\n' % ( i, sUrl, );
878 aoReasons.append(WuiTmLink(oIt.oFailureReason.sShort, WuiAdmin.ksScriptName,
879 { WuiAdmin.ksParamAction: WuiAdmin.ksActionFailureReasonDetails,
880 FailureReasonData.ksParam_idFailureReason: oIt.oFailureReason.idFailureReason },
881 sTitle = sReasonTitle));
882
883 return [
884 oEntry.tsCreated,
885 [ WuiTmLink('%s %s (%s)' % (oEntry.sProduct, oEntry.sVersion, oEntry.sType,),
886 WuiMain.ksScriptName, self._dRevLinkParams, sTitle = '%s' % (oEntry.sBranch,), fBracketed = False),
887 WuiSvnLinkWithTooltip(oEntry.iRevision, 'vbox'), ## @todo add sRepository TestResultListingData
888 WuiTmLink(self.ksShortDetailsLink, WuiAdmin.ksScriptName,
889 { WuiAdmin.ksParamAction: WuiAdmin.ksActionBuildDetails,
890 BuildData.ksParam_idBuild: oEntry.idBuild },
891 fBracketed = False),
892 ],
893 oValidationKit,
894 [ WuiTmLink(oEntry.sTestBoxName, WuiMain.ksScriptName, self._dTestBoxLinkParams, fBracketed = False,
895 sTitle = sTestBoxTitle),
896 WuiTmLink(self.ksShortDetailsLink, WuiAdmin.ksScriptName,
897 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails,
898 TestBoxData.ksParam_idTestBox: oEntry.idTestBox },
899 fBracketed = False),
900 WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oEntry.idTestBox, fBracketed = False), ],
901 '%s.%s' % (oEntry.sOs, oEntry.sArch),
902 [ WuiTmLink(sTestCaseName, WuiMain.ksScriptName, self._dTestCaseLinkParams, fBracketed = False,
903 sTitle = (oEntry.sBaseCmd + ' ' + oEntry.sArgs) if oEntry.sArgs else oEntry.sBaseCmd),
904 WuiTmLink(self.ksShortDetailsLink, WuiAdmin.ksScriptName,
905 { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestCaseDetails,
906 TestCaseData.ksParam_idTestCase: oEntry.idTestCase },
907 fBracketed = False),
908 WuiReportSummaryLink(ReportModelBase.ksSubTestCase, oEntry.idTestCase, fBracketed = False), ],
909 oEntry.tsElapsed,
910 aoTestSetLinks,
911 aoReasons
912 ];
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