def showTestCaseResultDetails( self, # pylint: disable=R0914,R0915 oTestResultTree, oTestSet, oBuildEx, oValidationKitEx, oTestBox, oTestGroup, oTestCaseEx, oTestVarEx): """Show detailed result""" def getTcDepsHtmlList(aoTestCaseData): """Get HTML <ul> list of Test Case name items""" if len(aoTestCaseData) > 0: sTmp = '<ul>' for oTestCaseData in aoTestCaseData: sTmp += '<li>%s</li>' % (webutils.escapeElem( oTestCaseData.sName), ) sTmp += '</ul>' else: sTmp = 'No items' return sTmp def getGrDepsHtmlList(aoGlobalResourceData): """Get HTML <ul> list of Global Resource name items""" if len(aoGlobalResourceData) > 0: sTmp = '<ul>' for oGlobalResourceData in aoGlobalResourceData: sTmp += '<li>%s</li>' % (webutils.escapeElem( oGlobalResourceData.sName), ) sTmp += '</ul>' else: sTmp = 'No items' return sTmp asHtml = [] # Test result + test set details. aoResultRows = [ WuiTmLink( oTestCaseEx.sName, self.oWuiAdmin.ksScriptName, { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestCaseDetails, TestCaseData.ksParam_idTestCase: oTestCaseEx.idTestCase, self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsConfig, }, fBracketed=False), ] if oTestCaseEx.sDescription is not None and len( oTestCaseEx.sDescription) > 0: aoResultRows.append([ oTestCaseEx.sDescription, ]) aoResultRows.append([ 'Status:', WuiRawHtml('<span class="tmspan-status-%s">%s</span>' % ( oTestResultTree.enmStatus, oTestResultTree.enmStatus, )) ]) if oTestResultTree.cErrors > 0: aoResultRows.append(('Errors:', oTestResultTree.cErrors)) aoResultRows.append(['Elapsed:', oTestResultTree.tsElapsed]) cSecCfgTimeout = oTestCaseEx.cSecTimeout if oTestVarEx.cSecTimeout is None else oTestVarEx.cSecTimeout cSecEffTimeout = cSecCfgTimeout * oTestBox.pctScaleTimeout / 100 aoResultRows.append([ 'Timeout:', '%s (%s sec)' % ( utils.formatIntervalSeconds(cSecEffTimeout), cSecEffTimeout, ) ]) if cSecEffTimeout != cSecCfgTimeout: aoResultRows.append([ 'Cfg Timeout:', '%s (%s sec)' % ( utils.formatIntervalSeconds(cSecCfgTimeout), cSecCfgTimeout, ) ]) aoResultRows += [ ('Started:', WuiTmLink( self.formatTsShort(oTestSet.tsCreated), WuiMain.ksScriptName, { WuiMain.ksParamAction: WuiMain.ksActionResultsUnGrouped, WuiMain.ksParamEffectiveDate: oTestSet.tsCreated, }, fBracketed=False)), ] if oTestSet.tsDone is not None: aoResultRows += [ ('Done:', WuiTmLink(self.formatTsShort(oTestSet.tsDone), WuiMain.ksScriptName, { WuiMain.ksParamAction: WuiMain.ksActionResultsUnGrouped, WuiMain.ksParamEffectiveDate: oTestSet.tsDone, }, fBracketed=False)) ] else: aoResultRows += [('Done:', 'Still running...')] aoResultRows += [('Config:', oTestSet.tsConfig)] if oTestVarEx.cGangMembers > 1: aoResultRows.append([ 'Member No:', '#%s (of %s)' % (oTestSet.iGangMemberNo, oTestVarEx.cGangMembers) ]) aoResultRows += [ ('Test Group:', WuiTmLink( oTestGroup.sName, self.oWuiAdmin.ksScriptName, { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestGroupDetails, TestGroupData.ksParam_idTestGroup: oTestGroup.idTestGroup, self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsConfig, }, fBracketed=False)), ] if oTestVarEx.sTestBoxReqExpr is not None: aoResultRows.append(['TestBox reqs:', oTestVarEx.sTestBoxReqExpr]) elif oTestCaseEx.sTestBoxReqExpr is not None or oTestVarEx.sTestBoxReqExpr is not None: aoResultRows.append(['TestBox reqs:', oTestCaseEx.sTestBoxReqExpr]) if oTestVarEx.sBuildReqExpr is not None: aoResultRows.append(['Build reqs:', oTestVarEx.sBuildReqExpr]) elif oTestCaseEx.sBuildReqExpr is not None or oTestVarEx.sBuildReqExpr is not None: aoResultRows.append(['Build reqs:', oTestCaseEx.sBuildReqExpr]) if oTestCaseEx.sValidationKitZips is not None and oTestCaseEx.sValidationKitZips != '@VALIDATIONKIT_ZIP@': aoResultRows.append( ['Validation Kit:', oTestCaseEx.sValidationKitZips]) if oTestCaseEx.aoDepTestCases is not None and len( oTestCaseEx.aoDepTestCases) > 0: aoResultRows.append([ 'Prereq. Test Cases:', oTestCaseEx.aoDepTestCases, getTcDepsHtmlList ]) if oTestCaseEx.aoDepGlobalResources is not None and len( oTestCaseEx.aoDepGlobalResources) > 0: aoResultRows.append([ 'Global Resources:', oTestCaseEx.aoDepGlobalResources, getGrDepsHtmlList ]) # Builds. aoBuildRows = [] if oBuildEx is not None: aoBuildRows += [ WuiTmLink( 'Build', self.oWuiAdmin.ksScriptName, { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionBuildDetails, BuildData.ksParam_idBuild: oBuildEx.idBuild, self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsCreated, }, fBracketed=False), ] self._anchorAndAppendBinaries(oBuildEx.sBinaries, aoBuildRows) aoBuildRows += [ ('Revision:', WuiSvnLinkWithTooltip(oBuildEx.iRevision, oBuildEx.oCat.sRepository, fBracketed=False)), ('Product:', oBuildEx.oCat.sProduct), ('Branch:', oBuildEx.oCat.sBranch), ('Type:', oBuildEx.oCat.sType), ('Version:', oBuildEx.sVersion), ('Created:', oBuildEx.tsCreated), ] if oBuildEx.uidAuthor is not None: aoBuildRows += [ ('Author ID:', oBuildEx.uidAuthor), ] if oBuildEx.sLogUrl is not None: aoBuildRows += [ ('Log:', WuiBuildLogLink(oBuildEx.sLogUrl, fBracketed=False)), ] aoValidationKitRows = [] if oValidationKitEx is not None: aoValidationKitRows += [ WuiTmLink( 'Validation Kit', self.oWuiAdmin.ksScriptName, { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionBuildDetails, BuildData.ksParam_idBuild: oValidationKitEx.idBuild, self.oWuiAdmin.ksParamEffectiveDate: oTestSet.tsCreated, }, fBracketed=False), ] self._anchorAndAppendBinaries(oValidationKitEx.sBinaries, aoValidationKitRows) aoValidationKitRows += [('Revision:', WuiSvnLink(oValidationKitEx.iRevision, fBracketed=False))] if oValidationKitEx.oCat.sProduct != 'VBox TestSuite': aoValidationKitRows += [ ('Product:', oValidationKitEx.oCat.sProduct), ] if oValidationKitEx.oCat.sBranch != 'trunk': aoValidationKitRows += [ ('Product:', oValidationKitEx.oCat.sBranch), ] if oValidationKitEx.oCat.sType != 'release': aoValidationKitRows += [ ('Type:', oValidationKitEx.oCat.sType), ] if oValidationKitEx.sVersion != '0.0.0': aoValidationKitRows += [ ('Version:', oValidationKitEx.sVersion), ] aoValidationKitRows += [ ('Created:', oValidationKitEx.tsCreated), ] if oValidationKitEx.uidAuthor is not None: aoValidationKitRows += [ ('Author ID:', oValidationKitEx.uidAuthor), ] if oValidationKitEx.sLogUrl is not None: aoValidationKitRows += [ ('Log:', WuiBuildLogLink(oValidationKitEx.sLogUrl, fBracketed=False)), ] # TestBox. aoTestBoxRows = [ WuiTmLink( oTestBox.sName, self.oWuiAdmin.ksScriptName, { self.oWuiAdmin.ksParamAction: self.oWuiAdmin.ksActionTestBoxDetails, TestBoxData.ksParam_idGenTestBox: oTestSet.idGenTestBox, }, fBracketed=False), ] if oTestBox.sDescription is not None and len( oTestBox.sDescription) > 0: aoTestBoxRows.append([ oTestBox.sDescription, ]) aoTestBoxRows += [ ('IP:', oTestBox.ip), #( 'UUID:', oTestBox.uuidSystem ), #( 'Enabled:', oTestBox.fEnabled ), #( 'Lom Kind:', oTestBox.enmLomKind ), #( 'Lom IP:', oTestBox.ipLom ), ('OS/Arch:', '%s.%s' % (oTestBox.sOs, oTestBox.sCpuArch)), ('OS Version:', oTestBox.sOsVersion), ('CPUs:', oTestBox.cCpus), ] if oTestBox.sCpuName is not None: aoTestBoxRows.append( ['CPU Name', oTestBox.sCpuName.replace(' ', ' ')]) if oTestBox.lCpuRevision is not None: # ASSUMING x86+AMD64 versioning scheme here. uFamily = (oTestBox.lCpuRevision >> 24) & 0xff uModel = (oTestBox.lCpuRevision >> 8) & 0xffff uStepping = oTestBox.lCpuRevision & 0xff aoTestBoxRows += [ ('CPU Family', '%u (%#x)' % ( uFamily, uFamily, )), ('CPU Model', '%u (%#x)' % ( uModel, uModel, )), ('CPU Stepping', '%u (%#x)' % ( uStepping, uStepping, )), ] asFeatures = [ oTestBox.sCpuVendor, ] if oTestBox.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt') if oTestBox.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging') if oTestBox.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest') if oTestBox.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU') aoTestBoxRows += [ ('Features:', u' '.join(asFeatures)), ('RAM size:', '%s MB' % (oTestBox.cMbMemory, )), ('Scratch Size:', '%s MB' % (oTestBox.cMbScratch, )), ('Scale Timeout:', '%s%%' % (oTestBox.pctScaleTimeout, )), ('Script Rev:', WuiSvnLink(oTestBox.iTestBoxScriptRev, fBracketed=False)), ('Python:', oTestBox.formatPythonVersion()), ('Pending Command:', oTestBox.enmPendingCmd), ] aoRows = [ aoResultRows, aoBuildRows, aoValidationKitRows, aoTestBoxRows, ] asHtml.append(self._htmlTable(aoRows)) # # Convert the tree to a list of events, values, message and files. # sHtmlEvents = '' sHtmlEvents += '<table class="tmtbl-events" id="tmtbl-events" width="100%">\n' sHtmlEvents += ' <tr class="tmheader">\n' \ ' <th>When</th>\n' \ ' <th></th>\n' \ ' <th>Elapsed</th>\n' \ ' <th>Event name</th>\n' \ ' <th colspan="2">Value (status)</th>' \ ' <th></th>\n' \ ' </tr>\n' sPrettyCmdLine = ' \\<br> \n'.join( webutils.escapeElem(oTestCaseEx.sBaseCmd + ' ' + oTestVarEx.sArgs).split()) (sTmp, _, cFailures) = self._recursivelyGenerateEvents(oTestResultTree, sPrettyCmdLine, '', 1, 0, oTestSet, 0) sHtmlEvents += sTmp sHtmlEvents += '</table>\n' # # Put it all together. # sHtml = '<table class="tmtbl-testresult-details-base" width="100%">\n' sHtml += ' <tr>\n' sHtml += ' <td valign="top" width="20%%">\n%s\n</td>\n' % ' <br>\n'.join( asHtml) sHtml += ' <td valign="top" width="80%" style="padding-left:6px">\n' sHtml += ' <h2>Events:</h2>\n' sHtml += ' <form action="#" method="get" id="graph-form">\n' \ ' <input type="hidden" name="%s" value="%s"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ % ( WuiMain.ksParamAction, WuiMain.ksActionGraphWiz, WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox, WuiMain.ksParamGraphWizBuildCatIds, oBuildEx.idBuildCategory, WuiMain.ksParamGraphWizTestCaseIds, oTestSet.idTestCase, WuiMain.ksParamGraphWizSrcTestSetId, oTestSet.idTestSet, ) if oTestSet.tsDone is not None: sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \ % ( WuiMain.ksParamEffectiveDate, oTestSet.tsDone, ) sHtml += ' <p>\n' sFormButton = '<button type="submit" onclick="%s">Show graphs</button>' \ % ( webutils.escapeAttr('addDynamicGraphInputs("graph-form", "main", "%s", "%s");' % (WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizDpi, )) ) sHtml += ' ' + sFormButton + '\n' sHtml += ' %s %s %s\n' \ % ( WuiTmLink('Log File', '', { WuiMain.ksParamAction: WuiMain.ksActionViewLog, WuiMain.ksParamLogSetId: oTestSet.idTestSet, }), WuiTmLink('Raw Log', '', { WuiMain.ksParamAction: WuiMain.ksActionGetFile, WuiMain.ksParamGetFileSetId: oTestSet.idTestSet, WuiMain.ksParamGetFileDownloadIt: False, }), WuiTmLink('Download Log', '', { WuiMain.ksParamAction: WuiMain.ksActionGetFile, WuiMain.ksParamGetFileSetId: oTestSet.idTestSet, WuiMain.ksParamGetFileDownloadIt: True, }), ) sHtml += ' </p>\n' if cFailures == 1: sHtml += ' <p>%s</p>\n' % (WuiTmLink('Jump to failure', '#failure-0'), ) elif cFailures > 1: sHtml += ' <p>Jump to failure: ' if cFailures <= 13: for iFailure in range(0, cFailures): sHtml += ' ' + WuiTmLink('#%u' % (iFailure, ), '#failure-%u' % (iFailure, )).toHtml() else: for iFailure in range(0, 6): sHtml += ' ' + WuiTmLink('#%u' % (iFailure, ), '#failure-%u' % (iFailure, )).toHtml() sHtml += ' ... ' for iFailure in range(cFailures - 6, cFailures): sHtml += ' ' + WuiTmLink('#%u' % (iFailure, ), '#failure-%u' % (iFailure, )).toHtml() sHtml += ' </p>\n' sHtml += sHtmlEvents sHtml += ' <p>' + sFormButton + '</p>\n' sHtml += ' </form>\n' sHtml += ' </td>\n' sHtml += ' </tr>\n' sHtml += '</table>\n' return ('Test Case result details', sHtml)
def _formatListEntry(self, iEntry): # pylint: disable=R0914 from testmanager.webui.wuiadmin import WuiAdmin oEntry = self._aoEntries[iEntry] # Lights outs managment. if oEntry.enmLomKind == TestBoxData.ksLomKind_ILOM: aoLom = [ WuiLinkBase('ILOM', 'https://%s/' % (oEntry.ipLom, ), fBracketed=False), ] elif oEntry.enmLomKind == TestBoxData.ksLomKind_ELOM: aoLom = [ WuiLinkBase('ELOM', 'http://%s/' % (oEntry.ipLom, ), fBracketed=False), ] elif oEntry.enmLomKind == TestBoxData.ksLomKind_AppleXserveLom: aoLom = ['Apple LOM'] elif oEntry.enmLomKind == TestBoxData.ksLomKind_None: aoLom = ['none'] else: aoLom = [ 'Unexpected enmLomKind value "%s"' % (oEntry.enmLomKind, ) ] if oEntry.ipLom is not None: if oEntry.enmLomKind in [ TestBoxData.ksLomKind_ILOM, TestBoxData.ksLomKind_ELOM ]: aoLom += [ WuiLinkBase('(ssh)', 'ssh://%s' % (oEntry.ipLom, ), fBracketed=False) ] aoLom += [WuiRawHtml('<br>'), '%s' % (oEntry.ipLom, )] # State and Last seen. if oEntry.oStatus is None: oSeen = WuiSpanText('tmspan-offline', 'Never') oState = '' else: oDelta = oEntry.tsCurrent - oEntry.oStatus.tsUpdated if oDelta.days <= 0 and oDelta.seconds <= self.kcSecMaxStatusDeltaAlive: oSeen = WuiSpanText( 'tmspan-online', u'%s\u00a0s\u00a0ago' % (oDelta.days * 24 * 3600 + oDelta.seconds, )) else: oSeen = WuiSpanText( 'tmspan-offline', u'%s' % (self.formatTsShort(oEntry.oStatus.tsUpdated), )) if oEntry.oStatus.idTestSet is None: oState = str(oEntry.oStatus.enmState) else: from testmanager.webui.wuimain import WuiMain oState = WuiTmLink( oEntry.oStatus.enmState, WuiMain.ksScriptName, # pylint: disable=R0204 { WuiMain.ksParamAction: WuiMain.ksActionTestResultDetails, TestSetData.ksParam_idTestSet: oEntry.oStatus.idTestSet, }, sTitle='#%u' % (oEntry.oStatus.idTestSet, ), fBracketed=False) # Comment oComment = self._formatCommentCell(oEntry.sComment) # Group links. aoGroups = [] for oInGroup in oEntry.aoInSchedGroups: oSchedGroup = oInGroup.oSchedGroup aoGroups.append( WuiTmLink(oSchedGroup.sName, WuiAdmin.ksScriptName, { WuiAdmin.ksParamAction: WuiAdmin.ksActionSchedGroupEdit, SchedGroupData.ksParam_idSchedGroup: oSchedGroup.idSchedGroup, }, sTitle='#%u' % (oSchedGroup.idSchedGroup, ), fBracketed=len(oEntry.aoInSchedGroups) > 1)) # Reformat the OS version to take less space. aoOs = ['N/A'] if oEntry.sOs is not None and oEntry.sOsVersion is not None and oEntry.sCpuArch: sOsVersion = oEntry.sOsVersion if sOsVersion[0] not in [ 'v', 'V', 'r', 'R'] \ and sOsVersion[0].isdigit() \ and sOsVersion.find('.') in range(4) \ and oEntry.sOs in [ 'linux', 'solaris', 'darwin', ]: sOsVersion = 'v' + sOsVersion sVer1 = sOsVersion sVer2 = None if oEntry.sOs == 'linux' or oEntry.sOs == 'darwin': iSep = sOsVersion.find(' / ') if iSep > 0: sVer1 = sOsVersion[:iSep].strip() sVer2 = sOsVersion[iSep + 3:].strip() sVer2 = sVer2.replace('Red Hat Enterprise Linux Server', 'RHEL') sVer2 = sVer2.replace('Oracle Linux Server', 'OL') elif oEntry.sOs == 'solaris': iSep = sOsVersion.find(' (') if iSep > 0 and sOsVersion[-1] == ')': sVer1 = sOsVersion[:iSep].strip() sVer2 = sOsVersion[iSep + 2:-1].strip() elif oEntry.sOs == 'win': iSep = sOsVersion.find('build') if iSep > 0: sVer1 = sOsVersion[:iSep].strip() sVer2 = 'B' + sOsVersion[iSep + 1:].strip() aoOs = [ WuiSpanText('tmspan-osarch', u'%s.%s' % ( oEntry.sOs, oEntry.sCpuArch, )), WuiSpanText( 'tmspan-osver1', sVer1.replace('-', u'\u2011'), ), ] if sVer2 is not None: aoOs += [ WuiRawHtml('<br>'), WuiSpanText('tmspan-osver2', sVer2.replace('-', u'\u2011')), ] # Format the CPU revision. oCpu = None if oEntry.lCpuRevision is not None and oEntry.sCpuVendor is not None and oEntry.sCpuName is not None: oCpu = [ u'%s (fam:%xh\u00a0m:%xh\u00a0s:%xh)' % ( oEntry.sCpuVendor, oEntry.getCpuFamily(), oEntry.getCpuModel(), oEntry.getCpuStepping(), ), WuiRawHtml('<br>'), oEntry.sCpuName, ] else: oCpu = [] if oEntry.sCpuVendor is not None: oCpu.append(oEntry.sCpuVendor) if oEntry.lCpuRevision is not None: oCpu.append('%#x' % (oEntry.lCpuRevision, )) if oEntry.sCpuName is not None: oCpu.append(oEntry.sCpuName) # Stuff cpu vendor and cpu/box features into one field. asFeatures = [] if oEntry.fCpuHwVirt is True: asFeatures.append(u'HW\u2011Virt') if oEntry.fCpuNestedPaging is True: asFeatures.append(u'Nested\u2011Paging') if oEntry.fCpu64BitGuest is True: asFeatures.append(u'64\u2011bit\u2011Guest') if oEntry.fChipsetIoMmu is True: asFeatures.append(u'I/O\u2011MMU') sFeatures = u' '.join(asFeatures) if asFeatures else u'' # Collection applicable actions. aoActions = [ WuiTmLink( 'Details', WuiAdmin.ksScriptName, { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxDetails, TestBoxData.ksParam_idTestBox: oEntry.idTestBox, WuiAdmin.ksParamEffectiveDate: self._tsEffectiveDate, }), ] if self._oDisp is None or not self._oDisp.isReadOnlyUser(): if isDbTimestampInfinity(oEntry.tsExpire): aoActions += [ WuiTmLink( 'Edit', WuiAdmin.ksScriptName, { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxEdit, TestBoxData.ksParam_idTestBox: oEntry.idTestBox, }), WuiTmLink( 'Remove', WuiAdmin.ksScriptName, { WuiAdmin.ksParamAction: WuiAdmin.ksActionTestBoxRemovePost, TestBoxData.ksParam_idTestBox: oEntry.idTestBox }, sConfirm='Are you sure that you want to remove %s (%s)?' % (oEntry.sName, oEntry.ip)), ] if oEntry.sOs not in [ 'win', 'os2', ] and oEntry.ip is not None: aoActions.append( WuiLinkBase( 'ssh', 'ssh://vbox@%s' % (oEntry.ip, ), )) return [ self._getCheckBoxColumn(iEntry, oEntry.idTestBox), [ WuiSpanText('tmspan-name', oEntry.sName), WuiRawHtml('<br>'), '%s' % (oEntry.ip, ), ], aoLom, [ '' if oEntry.fEnabled else 'disabled / ', oState, WuiRawHtml('<br>'), oSeen, ], oEntry.enmPendingCmd, oComment, WuiSvnLink(oEntry.iTestBoxScriptRev), oEntry.formatPythonVersion(), aoGroups, aoOs, oCpu, sFeatures, oEntry.cCpus if oEntry.cCpus is not None else 'N/A', utils.formatNumberNbsp(oEntry.cMbMemory) + u'\u00a0MB' if oEntry.cMbMemory is not None else 'N/A', utils.formatNumberNbsp(oEntry.cMbScratch) + u'\u00a0MB' if oEntry.cMbScratch is not None else 'N/A', aoActions, ]