VirtualBox

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

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

Fetch and show all failures reasons for a test in the main listing. The SQL is getting uglier and uglier...

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

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