def _getCheckBoxColumn(self, iEntry, sValue): """ Used by _formatListEntry implementations, returns a WuiRawHtmlBase object. """ _ = iEntry; return WuiRawHtml('<input type="checkbox" name="%s" value="%s">' % (webutils.escapeAttr(self._sCheckboxName), webutils.escapeAttr(unicode(sValue))));
def _debugRenderPanel(self): """ Renders a simple form for controlling WUI debugging. Returns the HTML for it. """ sHtml = '<div id="debug-panel">\n' \ ' <form id="debug-panel-form" type="get" action="#">\n'; for sKey, oValue in self._dParams.iteritems(): if sKey not in self.kasDbgParams: if hasattr(oValue, 'startswith'): sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \ % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oValue),); else: for oSubValue in oValue: sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \ % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oSubValue),); for aoCheckBox in ( [self.ksParamDbgSqlTrace, self._fDbgSqlTrace, 'SQL trace'], [self.ksParamDbgSqlExplain, self._fDbgSqlExplain, 'SQL explain'], ): sHtml += ' <input type="checkbox" name="%s" value="1"%s />%s\n' \ % (aoCheckBox[0], ' checked' if aoCheckBox[1] else '', aoCheckBox[2]); sHtml += ' <button type="submit">Apply</button>\n'; sHtml += ' </form>\n' \ '</div>\n'; return sHtml;
def addTextHidden(self, sName, sValue, sExtraAttribs = ''): """Adds a hidden text input.""" return self._add(' <div class="tmform-field-hidden">\n' ' <input name="%s" id="%s" type="text" hidden%s value="%s" class="tmform-hidden">\n' ' </div>\n' ' </li>\n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)) ));
def _debugRenderPanel(self): """ Renders a simple form for controlling WUI debugging. Returns the HTML for it. """ sHtml = '<div id="debug-panel">\n' \ ' <form id="debug-panel-form" type="get" action="#">\n'; for sKey, oValue in self._dParams.items(): if sKey not in self.kasDbgParams: if hasattr(oValue, 'startswith'): sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \ % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oValue),); else: for oSubValue in oValue: sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' \ % (webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oSubValue),); for aoCheckBox in ( [self.ksParamDbgSqlTrace, self._fDbgSqlTrace, 'SQL trace'], [self.ksParamDbgSqlExplain, self._fDbgSqlExplain, 'SQL explain'], ): sHtml += ' <input type="checkbox" name="%s" value="1"%s />%s\n' \ % (aoCheckBox[0], ' checked' if aoCheckBox[1] else '', aoCheckBox[2]); sHtml += ' <button type="submit">Apply</button>\n'; sHtml += ' </form>\n' \ '</div>\n'; return sHtml;
def addTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = '', sPostHtml = ''): """Adds a read-only text input.""" if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass); self._addLabel(sName, sLabel, sSubClass); return self._add(' <input name="%s" id="%s" type="text" readonly%s value="%s" class="tmform-input-readonly">%s\n' ' </div></div>\n' ' </li>\n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)), sPostHtml ));
def addMultilineTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = ''): """Adds a multiline read-only text input.""" if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp'): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) sNewValue = str(sValue) if not isinstance(sValue, list) else '\n'.join(sValue) return self._add(' <textarea name="%s" id="%s" readonly %s>%s</textarea>\n' ' </div></div>\n' ' </li>\n' % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue)))
def __init__(self, sSpanClass, sText, sTitle = None): if sTitle is None: WuiRawHtml.__init__(self, u'<span class="%s">%s</span>' % ( webutils.escapeAttr(sSpanClass), webutils.escapeElem(sText),)); else: WuiRawHtml.__init__(self, u'<span class="%s" title="%s">%s</span>' % ( webutils.escapeAttr(sSpanClass), webutils.escapeAttr(sTitle), webutils.escapeElem(sText),));
def _addList(self, sName, aoRows, sLabel, fUseTable=False, sId="dummy", sExtraAttribs=""): """ Adds a list of items to check. @param sName Name of HTML form element @param aoRows List of [sValue, fChecked, sName] sub-arrays. @param sLabel Label of HTML form element """ fReadOnly = self._fReadOnly ## @todo add this as a parameter. if fReadOnly: sExtraAttribs += ' readonly onclick="return false" onkeydown="return false"' self._addLabel(sName, sLabel, "list") if len(aoRows) == 0: return self._add("No items</div></div></li>") sNameEscaped = escapeAttr(sName) self._add(' <div class="tmform-checkboxes-container" id="%s">\n' % (escapeAttr(sId),)) if fUseTable: self._add(" <table>\n") for asRow in aoRows: assert len(asRow) == 3 # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add( " <tr>\n" ' <td><input type="checkbox" name="%s" value="%s"%s%s></td>\n' " <td>%s</td>\n" " </tr>\n" % ( sNameEscaped, escapeAttr(str(asRow[0])), " checked" if fChecked else "", sExtraAttribs, escapeElem(str(asRow[2])), ) ) self._add(" </table>\n") else: for asRow in aoRows: assert len(asRow) == 3 # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add( ' <div class="tmform-checkbox-holder">' '<input type="checkbox" name="%s" value="%s"%s%s> %s</input></div>\n' % ( sNameEscaped, escapeAttr(str(asRow[0])), " checked" if fChecked else "", sExtraAttribs, escapeElem(str(asRow[2])), ) ) return self._add(" </div></div></div>\n" " </li>\n")
def addCheckBox(self, sName, fChecked, sLabel, sExtraAttribs = ''): """Adds an check box.""" if self._fReadOnly: return self.addCheckBoxRO(sName, fChecked, sLabel, sExtraAttribs); self._addLabel(sName, sLabel, 'checkbox'); fChecked = self._reinterpretBool(fChecked); return self._add(' <input name="%s" id="%s" type="checkbox"%s%s value="1" class="tmform-checkbox">\n' ' </div></div>\n' ' </li>\n' % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs));
def addTextRO(self, sName, sValue, sLabel, sSubClass="string", sExtraAttribs="", sPostHtml=""): """Adds a read-only text input.""" if sSubClass not in ("int", "long", "string", "uuid", "timestamp", "wide"): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) return self._add( ' <input name="%s" id="%s" type="text" readonly%s value="%s" class="tmform-input-readonly">%s\n' " </div></div>\n" " </li>\n" % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)), sPostHtml) )
def addCheckBoxRO(self, sName, fChecked, sLabel, sExtraAttribs = ''): """Adds an readonly check box.""" self._addLabel(sName, sLabel, 'checkbox'); fChecked = self._reinterpretBool(fChecked); # Hack Alert! The onclick and onkeydown are for preventing editing and fake readonly/disabled. return self._add(' <input name="%s" id="%s" type="checkbox"%s readonly%s value="1" class="readonly"\n' ' onclick="return false" onkeydown="return false">\n' ' </div></div>\n' ' </li>\n' % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs));
def addCheckBox(self, sName, fChecked, sLabel, sExtraAttribs=""): """Adds an check box.""" if self._fReadOnly: return self.addCheckBoxRO(sName, fChecked, sLabel, sExtraAttribs) self._addLabel(sName, sLabel, "checkbox") fChecked = self._reinterpretBool(fChecked) return self._add( ' <input name="%s" id="%s" type="checkbox"%s%s value="1" class="tmform-checkbox">\n' " </div></div>\n" " </li>\n" % (escapeAttr(sName), escapeAttr(sName), " checked" if fChecked else "", sExtraAttribs) )
def addMultilineTextRO(self, sName, sValue, sLabel, sSubClass="string", sExtraAttribs=""): """Adds a multiline read-only text input.""" if sSubClass not in ("int", "long", "string", "uuid", "timestamp"): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) sNewValue = str(sValue) if not isinstance(sValue, list) else "\n".join(sValue) return self._add( ' <textarea name="%s" id="%s" readonly %s>%s</textarea>\n' " </div></div>\n" " </li>\n" % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue)) )
def _generateMenus(self): """ Generates the two menus, returning them as (sTopMenuItems, sSideMenuItems). """ # # We use the action to locate the side menu. # aasSideMenu = None for cchAction in range(len(self._sAction), 1, -1): sActionParam = "%s=%s" % (self.ksParamAction, self._sAction[:cchAction]) for aoItem in self._aaoMenus: if aoItem[1].find(sActionParam) > 0: aasSideMenu = aoItem[2] break for asSubItem in aoItem[2]: if asSubItem[1].find(sActionParam) > 0: aasSideMenu = aoItem[2] break if aasSideMenu is not None: break # # Top menu first. # sTopMenuItems = "" for aoItem in self._aaoMenus: if aasSideMenu is aoItem[2]: sTopMenuItems += '<li class="current_page_item">' else: sTopMenuItems += "<li>" sTopMenuItems += ( '<a href="' + webutils.escapeAttr(aoItem[1]) + '">' + webutils.escapeElem(aoItem[0]) + "</a></li>\n" ) # # Side menu (if found). # sActionParam = "%s=%s" % (self.ksParamAction, self._sAction) sSideMenuItems = "" if aasSideMenu is not None: for asSubItem in aasSideMenu: if asSubItem[1].find(sActionParam) > 0: sSideMenuItems += '<li class="current_page_item">' else: sSideMenuItems += "<li>" sSideMenuItems += ( '<a href="' + webutils.escapeAttr(asSubItem[1]) + '">' + webutils.escapeElem(asSubItem[0]) + "</a></li>\n" ) return (sTopMenuItems, sSideMenuItems)
def _generateMenus(self): """ Generates the two menus, returning them as (sTopMenuItems, sSideMenuItems). """ fReadOnly = self.isReadOnlyUser(); # # We use the action to locate the side menu. # aasSideMenu = None; for cchAction in range(len(self._sAction), 1, -1): sActionParam = '%s=%s' % (self.ksParamAction, self._sAction[:cchAction]); for aoItem in self._aaoMenus: if self._isMenuMatch(aoItem[1], sActionParam): aasSideMenu = aoItem[2]; break; for asSubItem in aoItem[2]: if self._isMenuMatch(asSubItem[1], sActionParam): aasSideMenu = aoItem[2]; break; if aasSideMenu is not None: break; # # Top menu first. # sTopMenuItems = ''; for aoItem in self._aaoMenus: if aasSideMenu is aoItem[2]: sTopMenuItems += '<li class="current_page_item">'; else: sTopMenuItems += '<li>'; sTopMenuItems += '<a href="' + webutils.escapeAttr(aoItem[1]) + '">' \ + webutils.escapeElem(aoItem[0]) + '</a></li>\n'; # # Side menu (if found). # sActionParam = '%s=%s' % (self.ksParamAction, self._sAction); sSideMenuItems = ''; if aasSideMenu is not None: for asSubItem in aasSideMenu: if asSubItem[1] is not None: if not asSubItem[2] or not fReadOnly: if self._isSideMenuMatch(asSubItem[1], sActionParam): sSideMenuItems += '<li class="current_page_item">'; else: sSideMenuItems += '<li>'; sSideMenuItems += '<a href="' + webutils.escapeAttr(asSubItem[1]) + '">' \ + webutils.escapeElem(asSubItem[0]) + '</a></li>\n'; else: sSideMenuItems += '<li class="subheader_item">' + webutils.escapeElem(asSubItem[0]) + '</li>'; return (sTopMenuItems, sSideMenuItems);
def _generateMenus(self): """ Generates the two menus, returning them as (sTopMenuItems, sSideMenuItems). """ # # We use the action to locate the side menu. # aasSideMenu = None for cchAction in range(len(self._sAction), 1, -1): sActionParam = '%s=%s' % (self.ksParamAction, self._sAction[:cchAction]) for aoItem in self._aaoMenus: if self._isMenuMatch(aoItem[1], sActionParam): aasSideMenu = aoItem[2] break for asSubItem in aoItem[2]: if self._isMenuMatch(asSubItem[1], sActionParam): aasSideMenu = aoItem[2] break if aasSideMenu is not None: break # # Top menu first. # sTopMenuItems = '' for aoItem in self._aaoMenus: if aasSideMenu is aoItem[2]: sTopMenuItems += '<li class="current_page_item">' else: sTopMenuItems += '<li>' sTopMenuItems += '<a href="' + webutils.escapeAttr(aoItem[1]) + '">' \ + webutils.escapeElem(aoItem[0]) + '</a></li>\n' # # Side menu (if found). # sActionParam = '%s=%s' % (self.ksParamAction, self._sAction) sSideMenuItems = '' if aasSideMenu is not None: for asSubItem in aasSideMenu: if self._isSideMenuMatch(asSubItem[1], sActionParam): sSideMenuItems += '<li class="current_page_item">' else: sSideMenuItems += '<li>' sSideMenuItems += '<a href="' + webutils.escapeAttr(asSubItem[1]) + '">' \ + webutils.escapeElem(asSubItem[0]) + '</a></li>\n' return (sTopMenuItems, sSideMenuItems)
def addComboBoxRO(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs = ''): """Adds a read-only combo box.""" self.addTextHidden(sName, sSelected); self._addLabel(sName, sLabel, 'combobox-readonly'); self._add(' <select name="%s" id="%s" disabled class="tmform-combobox"%s>\n' % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs)); for iValue, sText, _ in aoOptions: sValue = str(iValue); self._add(' <option value="%s"%s>%s</option>\n' % (escapeAttr(sValue), ' selected' if sValue == str(sSelected) else '', escapeElem(sText))); return self._add(' </select>\n' ' </div></div>\n' ' </li>\n' );
def _formatCommentCell(self, sComment, cMaxLines = 3, cchMaxLine = 63): """ Helper functions for formatting comment cell. Returns None or WuiRawHtml instance. """ # Nothing to do for empty comments. if sComment is None: return None; sComment = sComment.strip(); if len(sComment) == 0: return None; # Restrict the text if necessary, making the whole text available thru mouse-over. ## @todo this would be better done by java script or smth, so it could automatically adjust to the table size. if len(sComment) > cchMaxLine or sComment.count('\n') >= cMaxLines: sShortHtml = ''; for iLine, sLine in enumerate(sComment.split('\n')): if iLine >= cMaxLines: break; if iLine > 0: sShortHtml += '<br>\n'; if len(sLine) > cchMaxLine: sShortHtml += webutils.escapeElem(sLine[:(cchMaxLine - 3)]); sShortHtml += '...'; else: sShortHtml += webutils.escapeElem(sLine); return WuiRawHtml('<span class="tmcomment" title="%s">%s</span>' % (webutils.escapeAttr(sComment), sShortHtml,)); return WuiRawHtml('<span class="tmcomment">%s</span>' % (webutils.escapeElem(sComment).replace('\n', '<br>'),));
def _debugRenderPanel(self): """ Renders a simple form for controlling WUI debugging. Returns the HTML for it. """ sHtml = '<div id="debug-panel">\n' ' <form id="debug-panel-form" type="get" action="#">\n' for sKey, oValue in self._dParams.iteritems(): if sKey not in self.kasDbgParams: sHtml += ' <input type="hidden" name="%s" value="%s"/>\n' % ( webutils.escapeAttr(sKey), webutils.escapeAttrToStr(oValue), ) for aoCheckBox in ( [self.ksParamDbgSqlTrace, self._fDbgSqlTrace, "SQL trace"], [self.ksParamDbgSqlExplain, self._fDbgSqlExplain, "SQL explain"], ): sHtml += ' <input type="checkbox" name="%s" value="1"%s>%s</input>\n' % ( aoCheckBox[0], " checked" if aoCheckBox[1] else "", aoCheckBox[2], ) sHtml += ' <button type="submit">Apply</button>\n' sHtml += " </form>\n" "</div>\n" return sHtml
def toHtml(self): """ Returns a simple HTML anchor element. """ sExtraAttrs = self.sExtraAttrs; if self.sConfirm is not None: sExtraAttrs += 'onclick=\'return confirm("%s");\' ' % (webutils.escapeAttr(self.sConfirm),); if self.sTitle is not None: sExtraAttrs += 'title="%s" ' % (webutils.escapeAttr(self.sTitle),); if sExtraAttrs and sExtraAttrs[-1] != ' ': sExtraAttrs += ' '; sFmt = '[<a %shref="%s">%s</a>]'; if not self.fBracketed: sFmt = '<a %shref="%s">%s</a>'; return sFmt % (sExtraAttrs, webutils.escapeAttr(self.sUrl), webutils.escapeElem(self.sName));
def addComboBox(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs=""): """Adds a combo box.""" if self._fReadOnly: return self.addComboBoxRO(sName, sSelected, sLabel, aoOptions, sExtraAttribs) self._addLabel(sName, sLabel, "combobox") self._add( ' <select name="%s" id="%s" class="tmform-combobox"%s>\n' % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs) ) for iValue, sText, _ in aoOptions: sValue = str(iValue) self._add( ' <option value="%s"%s>%s</option>\n' % (escapeAttr(sValue), " selected" if sValue == str(sSelected) else "", escapeElem(sText)) ) return self._add(" </select>\n" " </div></div>\n" " </li>\n")
def toHtml(self): """ Returns a simple HTML anchor element. """ sExtraAttrs = self.sExtraAttrs if self.sConfirm is not None: sExtraAttrs += "onclick='return confirm(\"%s\");' " % (webutils.escapeAttr(self.sConfirm),) if self.sTitle is not None: sExtraAttrs += 'title="%s" ' % (webutils.escapeAttr(self.sTitle),) if len(sExtraAttrs) > 0 and sExtraAttrs[-1] != " ": sExtraAttrs += " " sFmt = '[<a %shref="%s">%s</a>]' if not self.fBracketed: sFmt = '<a %shref="%s">%s</a>' return sFmt % (sExtraAttrs, webutils.escapeAttr(self.sUrl), webutils.escapeElem(self.sName))
def _addLabel(self, sName, sLabel, sDivSubClass = 'normal'): """Internal worker for adding a label.""" if sName in self._dErrors: sError = self._dErrors[sName]; if utils.isString(sError): # List error trick (it's an associative array). return self._add(' <li>\n' ' <div class="tmform-field"><div class="tmform-field-%s">\n' ' <label for="%s" class="tmform-error-label">%s\n' ' <span class="tmform-error-desc">%s</span>\n' ' </label>\n' % (escapeAttr(sDivSubClass), escapeAttr(sName), escapeElem(sLabel), self._escapeErrorText(sError), ) ); return self._add(' <li>\n' ' <div class="tmform-field"><div class="tmform-field-%s">\n' ' <label for="%s">%s</label>\n' % (escapeAttr(sDivSubClass), escapeAttr(sName), escapeElem(sLabel)) );
def _formatSeriesNameForTable(self, oSet, idKey): oTestBox = oSet.dSubjects[idKey] sHtml = u'<td>' sHtml += WuiTestResultsForTestBoxLink( idKey, oTestBox.sName, self._dExtraTestResultsParams).toHtml() sHtml += u' ' sHtml += WuiTestBoxDetailsLinkShort(oTestBox).toHtml() sHtml += u' ' sHtml += WuiReportSummaryLink( ReportModelBase.ksSubTestBox, oTestBox.idTestBox, dExtraParams=self._dExtraParams).toHtml() sHtml += u'</td>' sOsAndVer = '%s %s' % ( oTestBox.sOs, oTestBox.sOsVersion.strip(), ) if len(sOsAndVer) < 22: sHtml += u'<td>%s</td>' % (webutils.escapeElem(sOsAndVer), ) else: # wonder if td.title works.. sHtml += u'<td title="%s" width="1%%" style="white-space:nowrap;">%s...</td>' \ % (webutils.escapeAttr(sOsAndVer), webutils.escapeElem(sOsAndVer[:20])) sHtml += u'<td>%s</td>' % (webutils.escapeElem( oTestBox.getArchBitString()), ) sHtml += u'<td>%s</td>' % (webutils.escapeElem( oTestBox.getPrettyCpuVendor()), ) sHtml += u'<td>%s' % (oTestBox.getPrettyCpuVersion(), ) if oTestBox.fCpuNestedPaging: sHtml += u', np' elif oTestBox.fCpuHwVirt: sHtml += u', hw' else: sHtml += u', raw' if oTestBox.fCpu64BitGuest: sHtml += u', 64' sHtml += u'</td>' return sHtml
def _formatCommentCell(self, sComment, cMaxLines = 3, cchMaxLine = 63): """ Helper functions for formatting comment cell. Returns None or WuiRawHtml instance. """ # Nothing to do for empty comments. if sComment is None: return None; sComment = sComment.strip(); if not sComment: return None; # Restrict the text if necessary, making the whole text available thru mouse-over. ## @todo this would be better done by java script or smth, so it could automatically adjust to the table size. if len(sComment) > cchMaxLine or sComment.count('\n') >= cMaxLines: sShortHtml = ''; for iLine, sLine in enumerate(sComment.split('\n')): if iLine >= cMaxLines: break; if iLine > 0: sShortHtml += '<br>\n'; if len(sLine) > cchMaxLine: sShortHtml += webutils.escapeElem(sLine[:(cchMaxLine - 3)]); sShortHtml += '...'; else: sShortHtml += webutils.escapeElem(sLine); return WuiRawHtml('<span class="tmcomment" title="%s">%s</span>' % (webutils.escapeAttr(sComment), sShortHtml,)); return WuiRawHtml('<span class="tmcomment">%s</span>' % (webutils.escapeElem(sComment).replace('\n', '<br>'),));
def show(self, fShowNavigation=True): """ Displays the list. Returns (Title, HTML) on success, raises exception on error. """ assert self._aoActions is not None assert self._sAction is not None sPageBody = ( '<script language="JavaScript">\n' "function toggle%s(oSource) {\n" " aoCheckboxes = document.getElementsByName('%s');\n" " for(var i in aoCheckboxes)\n" " aoCheckboxes[i].checked = oSource.checked;\n" "}\n" "</script>\n" % ("" if self._sId is None else self._sId, self._sCheckboxName) ) if fShowNavigation: sPageBody += self._generateNavigation("top") if len(self._aoEntries) > 0: sPageBody += '<form action="?%s" method="post" class="tmlistactionform">\n' % ( webutils.encodeUrlParams({WuiDispatcherBase.ksParamAction: self._sAction}), ) sPageBody += self._generateTable() sPageBody += ( " <label>Actions</label>\n" ' <select name="%s" id="%s-action-combo" class="tmlistactionform-combo">\n' % (webutils.escapeAttr(WuiDispatcherBase.ksParamListAction), webutils.escapeAttr(self._sId)) ) for oValue, sText, _ in self._aoActions: sPageBody += ' <option value="%s">%s</option>\n' % ( webutils.escapeAttr(unicode(oValue)), webutils.escapeElem(sText), ) sPageBody += " </select>\n" sPageBody += ' <input type="submit"></input>\n' sPageBody += "</form>\n" if fShowNavigation: sPageBody += self._generateNavigation("bottom") else: sPageBody += "<p>No entries.</p>" return (self._composeTitle(), sPageBody)
def addText(self, sName, sValue, sLabel, sSubClass='string', sExtraAttribs='', sPostHtml=''): """Adds a text input.""" if self._fReadOnly: return self.addTextRO(sName, sValue, sLabel, sSubClass, sExtraAttribs) if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass) self._addLabel(sName, sLabel, sSubClass) return self._add( ' <input name="%s" id="%s" type="text"%s value="%s">%s\n' ' </div></div>\n' ' </li>\n' % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sValue), sPostHtml))
def _addList(self, sName, aoRows, sLabel, fUseTable = False, sId = 'dummy', sExtraAttribs = ''): """ Adds a list of items to check. @param sName Name of HTML form element @param aoRows List of [sValue, fChecked, sName] sub-arrays. @param sLabel Label of HTML form element """ fReadOnly = self._fReadOnly; ## @todo add this as a parameter. if fReadOnly: sExtraAttribs += ' readonly onclick="return false" onkeydown="return false"'; self._addLabel(sName, sLabel, 'list'); if len(aoRows) == 0: return self._add('No items</div></div></li>') sNameEscaped = escapeAttr(sName); self._add(' <div class="tmform-checkboxes-container" id="%s">\n' % (escapeAttr(sId),)); if fUseTable: self._add(' <table>\n'); for asRow in aoRows: assert len(asRow) == 3; # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add(' <tr>\n' ' <td><input type="checkbox" name="%s" value="%s"%s%s></td>\n' ' <td>%s</td>\n' ' </tr>\n' % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs, escapeElem(str(asRow[2])), )); self._add(' </table>\n'); else: for asRow in aoRows: assert len(asRow) == 3; # Don't allow sloppy input data! fChecked = self._reinterpretBool(asRow[1]) self._add(' <div class="tmform-checkbox-holder">' '<input type="checkbox" name="%s" value="%s"%s%s> %s</input></div>\n' % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs, escapeElem(str(asRow[2])),)); return self._add(' </div></div></div>\n' ' </li>\n');
def addComboBox(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs=''): """Adds a combo box.""" if self._fReadOnly: return self.addComboBoxRO(sName, sSelected, sLabel, aoOptions, sExtraAttribs) self._addLabel(sName, sLabel, 'combobox') self._add( ' <select name="%s" id="%s" class="tmform-combobox"%s>\n' % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs)) for iValue, sText, _ in aoOptions: sValue = str(iValue) self._add(' <option value="%s"%s>%s</option>\n' % (escapeAttr(sValue), ' selected' if sValue == str(sSelected) else '', escapeElem(sText))) return self._add(' </select>\n' ' </div></div>\n' ' </li>\n')
def show(self, fShowNavigation=True): """ Displays the list. Returns (Title, HTML) on success, raises exception on error. """ assert self._aoActions is not None assert self._sAction is not None sPageBody = '<script language="JavaScript">\n' \ 'function toggle%s(oSource) {\n' \ ' aoCheckboxes = document.getElementsByName(\'%s\');\n' \ ' for(var i in aoCheckboxes)\n' \ ' aoCheckboxes[i].checked = oSource.checked;\n' \ '}\n' \ '</script>\n' \ % ('' if self._sId is None else self._sId, self._sCheckboxName,) if fShowNavigation: sPageBody += self._generateNavigation('top') if len(self._aoEntries) > 0: sPageBody += '<form action="?%s" method="post" class="tmlistactionform">\n' \ % (webutils.encodeUrlParams({WuiDispatcherBase.ksParamAction: self._sAction,}),) sPageBody += self._generateTable() sPageBody += ' <label>Actions</label>\n' \ ' <select name="%s" id="%s-action-combo" class="tmlistactionform-combo">\n' \ % (webutils.escapeAttr(WuiDispatcherBase.ksParamListAction), webutils.escapeAttr(self._sId),) for oValue, sText, _ in self._aoActions: sPageBody += ' <option value="%s">%s</option>\n' \ % (webutils.escapeAttr(unicode(oValue)), webutils.escapeElem(sText), ) sPageBody += ' </select>\n' sPageBody += ' <input type="submit"></input>\n' sPageBody += '</form>\n' if fShowNavigation: sPageBody += self._generateNavigation('bottom') else: sPageBody += '<p>No entries.</p>' return (self._composeTitle(), sPageBody)
def show(self): """ Generates the tooltip. Returns (sTitle, HTML). """ sHtml = '<div class="tmvcstimeline tmvcstimelinetooltip">\n' oCurDate = None for oEntry in self.aoEntries: oTsZulu = db.dbTimestampToZuluDatetime(oEntry.tsCreated) if oCurDate is None or oCurDate != oTsZulu.date(): if oCurDate is not None: sHtml += ' </dl>\n' oCurDate = oTsZulu.date() sHtml += ' <h2>%s:</h2>\n' \ ' <dl>\n' \ % (oTsZulu.strftime('%Y-%m-%d'),) sEntry = ' <dt id="r%s">' % (oEntry.iRevision, ) sEntry += '<a href="%s">' \ % ( webutils.escapeAttr(config.g_ksTracChangsetUrlFmt % { 'iRevision': oEntry.iRevision, 'sRepository': oEntry.sRepository,}), ) sEntry += '<span class="tmvcstimeline-time">%s</span>' % ( oTsZulu.strftime('%H:%MZ'), ) sEntry += ' Changeset <span class="tmvcstimeline-rev">[%s]</span>' % ( oEntry.iRevision, ) sEntry += ' by <span class="tmvcstimeline-author">%s</span>' % ( webutils.escapeElem(oEntry.sAuthor), ) sEntry += '</a>\n' sEntry += '</dt>\n' sEntry += ' <dd>%s</dd>\n' % (webutils.escapeElem( oEntry.sMessage), ) sHtml += sEntry if oCurDate is not None: sHtml += ' </dl>\n' sHtml += '</div>\n' return ('VCS History Tooltip', sHtml)
def _formatSeriesNameForTable(self, oSet, idKey): oTestBox = oSet.dSubjects[idKey]; sHtml = u'<td>'; sHtml += WuiReportSummaryLink(ReportModelBase.ksSubTestBox, oTestBox.idTestBox, sName = oTestBox.sName, dExtraParams = self._dExtraParams).toHtml(); sHtml += u' '; sHtml += WuiTestBoxDetailsLink(oTestBox.idTestBox).toHtml(); sHtml += u'</td>'; sOsAndVer = '%s %s' % (oTestBox.sOs, oTestBox.sOsVersion.strip(),); if len(sOsAndVer) < 22: sHtml += u'<td>%s</td>' % (webutils.escapeElem(sOsAndVer),); else: # wonder if td.title works.. sHtml += u'<td title="%s" width="1%%" style="white-space:nowrap;">%s...</td>' \ % (webutils.escapeAttr(sOsAndVer), webutils.escapeElem(sOsAndVer[:20])); sHtml += u'<td>%s</td>' % (webutils.escapeElem(oTestBox.getArchBitString()),); sHtml += u'<td>%s</td>' % (webutils.escapeElem(oTestBox.getPrettyCpuVendor()),); sHtml += u'<td>%s' % (oTestBox.getPrettyCpuVersion(),); if oTestBox.fCpuNestedPaging: sHtml += u', np'; elif oTestBox.fCpuHwVirt: sHtml += u', hw'; else: sHtml += u', raw'; if oTestBox.fCpu64BitGuest: sHtml += u', 64'; sHtml += u'</td>'; return sHtml;
def show(self): """ Generates the tooltip. Returns (sTitle, HTML). """ sHtml = '<div class="tmvcstimeline tmvcstimelinetooltip">\n'; oCurDate = None; for oEntry in self.aoEntries: oTsZulu = db.dbTimestampToZuluDatetime(oEntry.tsCreated); if oCurDate is None or oCurDate != oTsZulu.date(): if oCurDate is not None: sHtml += ' </dl>\n' oCurDate = oTsZulu.date(); sHtml += ' <h2>%s:</h2>\n' \ ' <dl>\n' \ % (oTsZulu.strftime('%Y-%m-%d'),); sEntry = ' <dt id="r%s">' % (oEntry.iRevision, ); sEntry += '<a href="%s">' \ % ( webutils.escapeAttr(config.g_ksTracChangsetUrlFmt % { 'iRevision': oEntry.iRevision, 'sRepository': oEntry.sRepository,}), ); sEntry += '<span class="tmvcstimeline-time">%s</span>' % ( oTsZulu.strftime('%H:%MZ'), ); sEntry += ' Changeset <span class="tmvcstimeline-rev">[%s]</span>' % ( oEntry.iRevision, ); sEntry += ' by <span class="tmvcstimeline-author">%s</span>' % ( webutils.escapeElem(oEntry.sAuthor), ); sEntry += '</a>\n'; sEntry += '</dt>\n'; sEntry += ' <dd>%s</dd>\n' % ( webutils.escapeElem(oEntry.sMessage), ); sHtml += sEntry; if oCurDate is not None: sHtml += ' </dl>\n'; sHtml += '</div>\n'; return ('VCS History Tooltip', sHtml);
def renderGraph(self): aoTable = self._oData.aoTable sReport = '<div class="tmbargraph">\n' # Figure the range. fpMin = self.fpMin fpMax = self.fpMax if self.fpMax is None: fpMax = float(aoTable[1].aoValues[0]) for i in range(1, len(aoTable)): for oValue in aoTable[i].aoValues: fpValue = float(oValue) if fpValue < fpMin: fpMin = fpValue if fpValue > fpMax: fpMax = fpValue assert fpMin >= 0 # Format the data. sReport += '<table class="tmbargraphl1" border="1" id="%s">\n' % ( escapeAttr(self._sId), ) for i in range(1, len(aoTable)): oRow = aoTable[i] sReport += ' <tr>\n' \ ' <td>%s</td>\n' \ ' <td height="100%%" width="%spx">\n' \ ' <table class="tmbargraphl2" height="100%%" width="100%%" ' \ 'border="0" cellspacing="0" cellpadding="0">\n' \ % (escapeElem(oRow.sName), escapeAttr(str(self.cxMaxBar + 2))) for j in range(len(oRow.aoValues)): oValue = oRow.aoValues[j] cPct = int(float(oValue) * 100 / fpMax) cxBar = int(float(oValue) * self.cxMaxBar / fpMax) sValue = escapeElem(oRow.asValues[j]) sColor = self.kasColors[j % len(self.kasColors)] sInvColor = 'white' if sColor[0] == '#' and len(sColor) == 7: sInvColor = '#%06x' % (~int(sColor[1:], 16) & 0xffffff, ) sReport += ' <tr><td>\n' \ ' <table class="tmbargraphl3" height="100%%" border="0" cellspacing="0" cellpadding="0">\n' \ ' <tr>\n' if cPct >= 99: sReport += ' <td width="%spx" nowrap bgcolor="%s" align="right" style="color:%s;">' \ '%s </td>\n' \ % (cxBar, sColor, sInvColor, sValue) elif cPct < 1: sReport += ' <td width="%spx" nowrap style="color:%s;">%s</td>\n' \ % (self.cxMaxBar - cxBar, sColor, sValue) elif cPct >= 50: sReport += ' <td width="%spx" nowrap bgcolor="%s" align="right" style="color:%s;">' \ '%s </td>\n' \ ' <td width="%spx" nowrap><div> </div></td>\n' \ % (cxBar, sColor, sInvColor, sValue, self.cxMaxBar - cxBar) else: sReport += ' <td width="%spx" nowrap bgcolor="%s"></td>\n' \ ' <td width="%spx" nowrap> %s</td>\n' \ % (cxBar, sColor, self.cxMaxBar - cxBar, sValue) sReport += ' </tr>\n' \ ' </table>\n' \ ' </td></tr>\n' sReport += ' </table>\n' \ ' </td>\n' \ ' </tr>\n' if i + 1 < len(aoTable) and len(oRow.aoValues) > 1: sReport += ' <tr></tr>\n' sReport += '</table>\n' sReport += '<div class="tmgraphlegend">\n' \ ' <p>Legend:\n' for j in range(len(aoTable[0].asValues)): sColor = self.kasColors[j % len(self.kasColors)] sReport += ' <font color="%s">■ %s</font>\n' \ % (sColor, escapeElem(aoTable[0].asValues[j])) sReport += ' </p>\n' \ '</div>\n' sReport += '</div>\n' return sReport
def _generateInteractiveForm(self): """ Generates the HTML for the interactive form. Returns (sTopOfForm, sEndOfForm) """ # # The top of the form. # sTop = '<form action="#" method="get" id="graphwiz-form">\n' \ ' <input type="hidden" name="%s" value="%s"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ % ( WuiMain.ksParamAction, WuiMain.ksActionGraphWiz, WuiMain.ksParamGraphWizSrcTestSetId, self._dParams[WuiMain.ksParamGraphWizSrcTestSetId], ) sTop += ' <div id="graphwiz-nav">\n' sTop += ' <script type="text/javascript">\n' \ ' window.onresize = function(){ return graphwizOnResizeRecalcWidth("graphwiz-nav", "%s"); }\n' \ ' window.onload = function(){ return graphwizOnLoadRememberWidth("graphwiz-nav"); }\n' \ ' </script>\n' \ % ( WuiMain.ksParamGraphWizWidth, ) # # Top: First row. # sTop += ' <div id="graphwiz-top-1">\n' # time. sNow = self._dParams[WuiMain.ksParamEffectiveDate] if sNow is None: sNow = '' sTop += ' <div id="graphwiz-time">\n' sTop += ' <label for="%s">Starting:</label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-time-input"/>\n' \ % ( WuiMain.ksParamEffectiveDate, WuiMain.ksParamEffectiveDate, WuiMain.ksParamEffectiveDate, sNow, ) sTop += ' <input type="hidden" name="%s" value="%u"/>\n' % ( WuiMain.ksParamReportPeriods, 1, ) sTop += ' <label for="%s"> Going back:\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-period-input"/>\n' \ % ( WuiMain.ksParamReportPeriodInHours, WuiMain.ksParamReportPeriodInHours, WuiMain.ksParamReportPeriodInHours, utils.formatIntervalHours(self._dParams[WuiMain.ksParamReportPeriodInHours]) ) sTop += ' </div>\n' # Graph options top row. sTop += ' <div id="graphwiz-top-options-1">\n' # graph type. sTop += ' <label for="%s">Graph:</label>\n' \ ' <select name="%s" id="%s">\n' \ % ( WuiMain.ksParamGraphWizImpl, WuiMain.ksParamGraphWizImpl, WuiMain.ksParamGraphWizImpl, ) for (sImpl, sDesc) in WuiMain.kaasGraphWizImplCombo: sTop += ' <option value="%s"%s>%s</option>\n' \ % (sImpl, ' selected' if sImpl == self._dParams[WuiMain.ksParamGraphWizImpl] else '', sDesc) sTop += ' </select>\n' # graph size. sTop += ' <label for="%s">Graph size:</label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-pixel-input"> x\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-pixel-input">\n' \ ' <label for="%s">Dpi:</label>'\ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-dpi-input">\n' \ ' <button type="button" onclick="%s">Defaults</button>\n' \ % ( WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizWidth, self._dParams[WuiMain.ksParamGraphWizWidth], WuiMain.ksParamGraphWizHeight, WuiMain.ksParamGraphWizHeight, self._dParams[WuiMain.ksParamGraphWizHeight], WuiMain.ksParamGraphWizDpi, WuiMain.ksParamGraphWizDpi, WuiMain.ksParamGraphWizDpi, self._dParams[WuiMain.ksParamGraphWizDpi], webutils.escapeAttr('return graphwizSetDefaultSizeValues("graphwiz-nav", "%s", "%s", "%s");' % ( WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizHeight, WuiMain.ksParamGraphWizDpi )), ) sTop += ' </div>\n' # (options row 1) sTop += ' </div>\n' # (end of row 1) # # Top: Second row. # sTop += ' <div id="graphwiz-top-2">\n' # Submit sFormButton = '<button type="submit">Refresh</button>\n' sTop += ' <div id="graphwiz-top-submit">' + sFormButton + '</div>\n' # Options. sTop += ' <div id="graphwiz-top-options-2">\n' sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s/>\n' \ ' <label for="%s">Tabular data</label>\n' \ % ( WuiMain.ksParamGraphWizTabular, WuiMain.ksParamGraphWizTabular, ' checked' if self._dParams[WuiMain.ksParamGraphWizTabular] else '', WuiMain.ksParamGraphWizTabular) if hasattr(self.oGraphClass, 'setXkcdStyle'): sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s/>\n' \ ' <label for="%s">xkcd-style</label>\n' \ % ( WuiMain.ksParamGraphWizXkcdStyle, WuiMain.ksParamGraphWizXkcdStyle, ' checked' if self._dParams[WuiMain.ksParamGraphWizXkcdStyle] else '', WuiMain.ksParamGraphWizXkcdStyle) elif self._dParams[WuiMain.ksParamGraphWizXkcdStyle]: sTop += ' <input type="hidden" name="%s" id="%s" value="1"/>\n' \ % ( WuiMain.ksParamGraphWizXkcdStyle, WuiMain.ksParamGraphWizXkcdStyle, ) if not hasattr(self.oGraphClass, 'kfNoErrorBarsSupport'): sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s title="%s"/>\n' \ ' <label for="%s">Error bars,</label>\n' \ ' <label for="%s">max: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-maxerrorbar-input" title="%s"/>\n' \ % ( WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizErrorBarY, ' checked' if self._dParams[WuiMain.ksParamGraphWizErrorBarY] else '', 'Error bars shows some of the max and min results on the Y-axis.', WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, self._dParams[WuiMain.ksParamGraphWizMaxErrorBarY], 'Maximum number of Y-axis error bar per graph. (Too many makes it unreadable.)' ) else: if self._dParams[WuiMain.ksParamGraphWizErrorBarY]: sTop += '<input type="hidden" name="%s" id="%s" value="1">\n' \ % ( WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizErrorBarY, ) sTop += '<input type="hidden" name="%s" id="%s" value="%u">\n' \ % ( WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, self._dParams[WuiMain.ksParamGraphWizMaxErrorBarY], ) sTop += ' <label for="%s">Font size: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-fontsize-input"/>\n' \ % ( WuiMain.ksParamGraphWizFontSize, WuiMain.ksParamGraphWizFontSize, WuiMain.ksParamGraphWizFontSize, self._dParams[WuiMain.ksParamGraphWizFontSize], ) sTop += ' <label for="%s">Data series: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-maxpergraph-input" title="%s"/>\n' \ % ( WuiMain.ksParamGraphWizMaxPerGraph, WuiMain.ksParamGraphWizMaxPerGraph, WuiMain.ksParamGraphWizMaxPerGraph, self._dParams[WuiMain.ksParamGraphWizMaxPerGraph], 'Max data series per graph.' ) sTop += ' </div>\n' # (options row 2) sTop += ' </div>\n' # (end of row 2) sTop += ' </div>\n' # end of top. # # The end of the page selection. # sEnd = ' <div id="graphwiz-end-selection">\n' # # Testbox selection # aidTestBoxes = list(self._dParams[WuiMain.ksParamGraphWizTestBoxIds]) sEnd += ' <div id="graphwiz-testboxes" class="graphwiz-end-selection-group">\n' \ ' <h3>TestBox Selection:</h3>\n' \ ' <ol class="tmgraph-testboxes">\n' # Get a list of eligible testboxes from the DB. for oTestBox in self._oModel.getEligibleTestBoxes(): try: aidTestBoxes.remove(oTestBox.idTestBox) except: sChecked = '' else: sChecked = ' checked' sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-tb-%u"%s/>' \ '<label for="gw-tb-%u">%s</label></li>\n' \ % ( WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox, oTestBox.idTestBox, sChecked, oTestBox.idTestBox, oTestBox.sName) # List testboxes that have been checked in a different period or something. for idTestBox in aidTestBoxes: oTestBox = self._oModel.oCache.getTestBox(idTestBox) sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-tb-%u" checked/>' \ '<label for="gw-tb-%u">%s</label></li>\n' \ % ( WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox, oTestBox.idTestBox, oTestBox.idTestBox, oTestBox.sName) sEnd += ' </ol>\n' \ ' </div>\n' # # Build category selection. # aidBuildCategories = list( self._dParams[WuiMain.ksParamGraphWizBuildCatIds]) sEnd += ' <div id="graphwiz-buildcategories" class="graphwiz-end-selection-group">\n' \ ' <h3>Build Category Selection:</h3>\n' \ ' <ol class="tmgraph-buildcategories">\n' for oBuildCat in self._oModel.getEligibleBuildCategories(): try: aidBuildCategories.remove(oBuildCat.idBuildCategory) except: sChecked = '' else: sChecked = ' checked' sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-bc-%u" %s/>' \ '<label for="gw-bc-%u">%s / %s / %s / %s</label></li>\n' \ % ( WuiMain.ksParamGraphWizBuildCatIds, oBuildCat.idBuildCategory, oBuildCat.idBuildCategory, sChecked, oBuildCat.idBuildCategory, oBuildCat.sProduct, oBuildCat.sBranch, oBuildCat.sType, ' & '.join(oBuildCat.asOsArches) ) assert len(aidBuildCategories) == 0 # SQL should return all currently selected. sEnd += ' </ol>\n' \ ' </div>\n' # # Testcase variations. # sEnd += ' <div id="graphwiz-testcase-variations" class="graphwiz-end-selection-group">\n' \ ' <h3>Miscellaneous:</h3>\n' \ ' <ol>' sEnd += ' <li>\n' \ ' <input type="checkbox" id="%s" name="%s" value="1"%s/>\n' \ ' <label for="%s">Separate by testcase variation.</label>\n' \ ' </li>\n' \ % ( WuiMain.ksParamGraphWizSepTestVars, WuiMain.ksParamGraphWizSepTestVars, ' checked' if self._dParams[WuiMain.ksParamGraphWizSepTestVars] else '', WuiMain.ksParamGraphWizSepTestVars ) sEnd += ' <li>\n' \ ' <lable for="%s">Test case ID:</label>\n' \ ' <input type="text" id="%s" name="%s" value="%s" readonly/>\n' \ ' </li>\n' \ % ( WuiMain.ksParamGraphWizTestCaseIds, WuiMain.ksParamGraphWizTestCaseIds, WuiMain.ksParamGraphWizTestCaseIds, ','.join([str(i) for i in self._dParams[WuiMain.ksParamGraphWizTestCaseIds]]), ) sEnd += ' </ol>\n' \ ' </div>\n' #sEnd += ' <h3> </h3>\n'; # # Finish up the form. # sEnd += ' <div id="graphwiz-end-submit"><p>' + sFormButton + '</p></div>\n' sEnd += ' </div>\n' \ '</form>\n' return (sTop, sEnd)
def renderGraph(self): aoTable = self._oData.aoTable; sReport = '<div class="tmbargraph">\n'; # Figure the range. fpMin = self.fpMin; fpMax = self.fpMax; if self.fpMax is None: fpMax = float(aoTable[1].aoValues[0]); for i in range(1, len(aoTable)): for oValue in aoTable[i].aoValues: fpValue = float(oValue); if fpValue < fpMin: fpMin = fpValue; if fpValue > fpMax: fpMax = fpValue; assert fpMin >= 0; # Format the data. sReport += '<table class="tmbargraphl1" border="1" id="%s">\n' % (escapeAttr(self._sId),); for i in range(1, len(aoTable)): oRow = aoTable[i]; sReport += ' <tr>\n' \ ' <td>%s</td>\n' \ ' <td height="100%%" width="%spx">\n' \ ' <table class="tmbargraphl2" height="100%%" width="100%%" ' \ 'border="0" cellspacing="0" cellpadding="0">\n' \ % (escapeElem(oRow.sName), escapeAttr(str(self.cxMaxBar + 2))); for j in range(len(oRow.aoValues)): oValue = oRow.aoValues[j]; cPct = int(float(oValue) * 100 / fpMax); cxBar = int(float(oValue) * self.cxMaxBar / fpMax); sValue = escapeElem(oRow.asValues[j]); sColor = self.kasColors[j % len(self.kasColors)]; sReport += ' <tr><td>\n' \ ' <table class="tmbargraphl3" height="100%%" border="0" cellspacing="0" cellpadding="0">\n' \ ' <tr>\n'; if cPct >= 99: sReport += ' <td width="%spx" nowrap bgcolor="%s" align="right">%s </td>\n' \ % (cxBar, sColor, sValue); elif cPct < 1: sReport += ' <td width="%spx" nowrap style="color:%s;">%s</td>\n' \ % (self.cxMaxBar - cxBar, sColor, sValue); elif cPct >= 50: sReport += ' <td width="%spx" nowrap bgcolor="%s" align="right">%s </td>\n' \ ' <td width="%spx" nowrap><div> </div></td>\n' \ % (cxBar, sColor, sValue, self.cxMaxBar - cxBar); else: sReport += ' <td width="%spx" nowrap bgcolor="%s"></td>\n' \ ' <td width="%spx" nowrap> %s</td>\n' \ % (cxBar, sColor, self.cxMaxBar - cxBar, sValue); sReport += ' </tr>\n' \ ' </table>\n' \ ' </td></tr>\n' sReport += ' </table>\n' \ ' </td>\n' \ ' </tr>\n'; if i + 1 < len(aoTable) and len(oRow.aoValues) > 1: sReport += ' <tr></tr>\n' sReport += '</table>\n'; sReport += '<div class="tmgraphlegend">\n' \ ' <p>Legend:\n'; for j in range(len(aoTable[0].asValues)): sColor = self.kasColors[j % len(self.kasColors)]; sReport += ' <font color="%s">■ %s</font>\n' \ % (sColor, escapeElem(aoTable[0].asValues[j])); sReport += ' </p>\n' \ '</div>\n'; sReport += '</div>\n'; return sReport;
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 __init__(self, sSpanClass, sText): WuiRawHtml.__init__( self, u'<span class="%s">%s</span>' % ( webutils.escapeAttr(sSpanClass), webutils.escapeElem(sText), ))
def _generateInteractiveForm(self): """ Generates the HTML for the interactive form. Returns (sTopOfForm, sEndOfForm) """ # # The top of the form. # sTop = '<form action="#" method="get" id="graphwiz-form">\n' \ ' <input type="hidden" name="%s" value="%s"/>\n' \ ' <input type="hidden" name="%s" value="%u"/>\n' \ % ( WuiMain.ksParamAction, WuiMain.ksActionGraphWiz, WuiMain.ksParamGraphWizSrcTestSetId, self._dParams[WuiMain.ksParamGraphWizSrcTestSetId], ); sTop += ' <div id="graphwiz-nav">\n'; sTop += ' <script type="text/javascript">\n' \ ' window.onresize = function(){ return graphwizOnResizeRecalcWidth("graphwiz-nav", "%s"); }\n' \ ' window.onload = function(){ return graphwizOnLoadRememberWidth("graphwiz-nav"); }\n' \ ' </script>\n' \ % ( WuiMain.ksParamGraphWizWidth, ); # # Top: First row. # sTop += ' <div id="graphwiz-top-1">\n'; # time. sNow = self._dParams[WuiMain.ksParamEffectiveDate]; if sNow is None: sNow = ''; sTop += ' <div id="graphwiz-time">\n'; sTop += ' <label for="%s">Starting:</label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-time-input"/>\n' \ % ( WuiMain.ksParamEffectiveDate, WuiMain.ksParamEffectiveDate, WuiMain.ksParamEffectiveDate, sNow, ); sTop += ' <input type="hidden" name="%s" value="%u"/>\n' % ( WuiMain.ksParamReportPeriods, 1, ); sTop += ' <label for="%s"> Going back:\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-period-input"/>\n' \ % ( WuiMain.ksParamReportPeriodInHours, WuiMain.ksParamReportPeriodInHours, WuiMain.ksParamReportPeriodInHours, utils.formatIntervalHours(self._dParams[WuiMain.ksParamReportPeriodInHours]) ); sTop += ' </div>\n'; # Graph options top row. sTop += ' <div id="graphwiz-top-options-1">\n'; # graph type. sTop += ' <label for="%s">Graph:</label>\n' \ ' <select name="%s" id="%s">\n' \ % ( WuiMain.ksParamGraphWizImpl, WuiMain.ksParamGraphWizImpl, WuiMain.ksParamGraphWizImpl, ); for (sImpl, sDesc) in WuiMain.kaasGraphWizImplCombo: sTop += ' <option value="%s"%s>%s</option>\n' \ % (sImpl, ' selected' if sImpl == self._dParams[WuiMain.ksParamGraphWizImpl] else '', sDesc); sTop += ' </select>\n'; # graph size. sTop += ' <label for="%s">Graph size:</label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-pixel-input"> x\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-pixel-input">\n' \ ' <label for="%s">Dpi:</label>'\ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-dpi-input">\n' \ ' <button type="button" onclick="%s">Defaults</button>\n' \ % ( WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizWidth, self._dParams[WuiMain.ksParamGraphWizWidth], WuiMain.ksParamGraphWizHeight, WuiMain.ksParamGraphWizHeight, self._dParams[WuiMain.ksParamGraphWizHeight], WuiMain.ksParamGraphWizDpi, WuiMain.ksParamGraphWizDpi, WuiMain.ksParamGraphWizDpi, self._dParams[WuiMain.ksParamGraphWizDpi], webutils.escapeAttr('return graphwizSetDefaultSizeValues("graphwiz-nav", "%s", "%s", "%s");' % ( WuiMain.ksParamGraphWizWidth, WuiMain.ksParamGraphWizHeight, WuiMain.ksParamGraphWizDpi )), ); sTop += ' </div>\n'; # (options row 1) sTop += ' </div>\n'; # (end of row 1) # # Top: Second row. # sTop += ' <div id="graphwiz-top-2">\n'; # Submit sFormButton = '<button type="submit">Refresh</button>\n'; sTop += ' <div id="graphwiz-top-submit">' + sFormButton + '</div>\n'; # Options. sTop += ' <div id="graphwiz-top-options-2">\n'; sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s/>\n' \ ' <label for="%s">Tabular data</label>\n' \ % ( WuiMain.ksParamGraphWizTabular, WuiMain.ksParamGraphWizTabular, ' checked' if self._dParams[WuiMain.ksParamGraphWizTabular] else '', WuiMain.ksParamGraphWizTabular); if hasattr(self.oGraphClass, 'setXkcdStyle'): sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s/>\n' \ ' <label for="%s">xkcd-style</label>\n' \ % ( WuiMain.ksParamGraphWizXkcdStyle, WuiMain.ksParamGraphWizXkcdStyle, ' checked' if self._dParams[WuiMain.ksParamGraphWizXkcdStyle] else '', WuiMain.ksParamGraphWizXkcdStyle); elif self._dParams[WuiMain.ksParamGraphWizXkcdStyle]: sTop += ' <input type="hidden" name="%s" id="%s" value="1"/>\n' \ % ( WuiMain.ksParamGraphWizXkcdStyle, WuiMain.ksParamGraphWizXkcdStyle, ); if not hasattr(self.oGraphClass, 'kfNoErrorBarsSupport'): sTop += ' <input type="checkbox" name="%s" id="%s" value="1"%s title="%s"/>\n' \ ' <label for="%s">Error bars,</label>\n' \ ' <label for="%s">max: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-maxerrorbar-input" title="%s"/>\n' \ % ( WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizErrorBarY, ' checked' if self._dParams[WuiMain.ksParamGraphWizErrorBarY] else '', 'Error bars shows some of the max and min results on the Y-axis.', WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, self._dParams[WuiMain.ksParamGraphWizMaxErrorBarY], 'Maximum number of Y-axis error bar per graph. (Too many makes it unreadable.)' ); else: if self._dParams[WuiMain.ksParamGraphWizErrorBarY]: sTop += '<input type="hidden" name="%s" id="%s" value="1">\n' \ % ( WuiMain.ksParamGraphWizErrorBarY, WuiMain.ksParamGraphWizErrorBarY, ); sTop += '<input type="hidden" name="%s" id="%s" value="%u">\n' \ % ( WuiMain.ksParamGraphWizMaxErrorBarY, WuiMain.ksParamGraphWizMaxErrorBarY, self._dParams[WuiMain.ksParamGraphWizMaxErrorBarY], ); sTop += ' <label for="%s">Font size: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-fontsize-input"/>\n' \ % ( WuiMain.ksParamGraphWizFontSize, WuiMain.ksParamGraphWizFontSize, WuiMain.ksParamGraphWizFontSize, self._dParams[WuiMain.ksParamGraphWizFontSize], ); sTop += ' <label for="%s">Data series: </label>\n' \ ' <input type="text" name="%s" id="%s" value="%s" class="graphwiz-maxpergraph-input" title="%s"/>\n' \ % ( WuiMain.ksParamGraphWizMaxPerGraph, WuiMain.ksParamGraphWizMaxPerGraph, WuiMain.ksParamGraphWizMaxPerGraph, self._dParams[WuiMain.ksParamGraphWizMaxPerGraph], 'Max data series per graph.' ); sTop += ' </div>\n'; # (options row 2) sTop += ' </div>\n'; # (end of row 2) sTop += ' </div>\n'; # end of top. # # The end of the page selection. # sEnd = ' <div id="graphwiz-end-selection">\n'; # # Testbox selection # aidTestBoxes = list(self._dParams[WuiMain.ksParamGraphWizTestBoxIds]); sEnd += ' <div id="graphwiz-testboxes" class="graphwiz-end-selection-group">\n' \ ' <h3>TestBox Selection:</h3>\n' \ ' <ol class="tmgraph-testboxes">\n'; # Get a list of eligible testboxes from the DB. for oTestBox in self._oModel.getEligibleTestBoxes(): try: aidTestBoxes.remove(oTestBox.idTestBox); except: sChecked = ''; else: sChecked = ' checked'; sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-tb-%u"%s/>' \ '<label for="gw-tb-%u">%s</label></li>\n' \ % ( WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox, oTestBox.idTestBox, sChecked, oTestBox.idTestBox, oTestBox.sName); # List testboxes that have been checked in a different period or something. for idTestBox in aidTestBoxes: oTestBox = self._oModel.oCache.getTestBox(idTestBox); sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-tb-%u" checked/>' \ '<label for="gw-tb-%u">%s</label></li>\n' \ % ( WuiMain.ksParamGraphWizTestBoxIds, oTestBox.idTestBox, oTestBox.idTestBox, oTestBox.idTestBox, oTestBox.sName); sEnd += ' </ol>\n' \ ' </div>\n'; # # Build category selection. # aidBuildCategories = list(self._dParams[WuiMain.ksParamGraphWizBuildCatIds]); sEnd += ' <div id="graphwiz-buildcategories" class="graphwiz-end-selection-group">\n' \ ' <h3>Build Category Selection:</h3>\n' \ ' <ol class="tmgraph-buildcategories">\n'; for oBuildCat in self._oModel.getEligibleBuildCategories(): try: aidBuildCategories.remove(oBuildCat.idBuildCategory); except: sChecked = ''; else: sChecked = ' checked'; sEnd += ' <li><input type="checkbox" name="%s" value="%s" id="gw-bc-%u" %s/>' \ '<label for="gw-bc-%u">%s / %s / %s / %s</label></li>\n' \ % ( WuiMain.ksParamGraphWizBuildCatIds, oBuildCat.idBuildCategory, oBuildCat.idBuildCategory, sChecked, oBuildCat.idBuildCategory, oBuildCat.sProduct, oBuildCat.sBranch, oBuildCat.sType, ' & '.join(oBuildCat.asOsArches) ); assert len(aidBuildCategories) == 0; # SQL should return all currently selected. sEnd += ' </ol>\n' \ ' </div>\n'; # # Testcase variations. # sEnd += ' <div id="graphwiz-testcase-variations" class="graphwiz-end-selection-group">\n' \ ' <h3>Miscellaneous:</h3>\n' \ ' <ol>'; sEnd += ' <li>\n' \ ' <input type="checkbox" id="%s" name="%s" value="1"%s/>\n' \ ' <label for="%s">Separate by testcase variation.</label>\n' \ ' </li>\n' \ % ( WuiMain.ksParamGraphWizSepTestVars, WuiMain.ksParamGraphWizSepTestVars, ' checked' if self._dParams[WuiMain.ksParamGraphWizSepTestVars] else '', WuiMain.ksParamGraphWizSepTestVars ); sEnd += ' <li>\n' \ ' <lable for="%s">Test case ID:</label>\n' \ ' <input type="text" id="%s" name="%s" value="%s" readonly/>\n' \ ' </li>\n' \ % ( WuiMain.ksParamGraphWizTestCaseIds, WuiMain.ksParamGraphWizTestCaseIds, WuiMain.ksParamGraphWizTestCaseIds, ','.join([str(i) for i in self._dParams[WuiMain.ksParamGraphWizTestCaseIds]]), ); sEnd += ' </ol>\n' \ ' </div>\n'; #sEnd += ' <h3> </h3>\n'; # # Finish up the form. # sEnd += ' <div id="graphwiz-end-submit"><p>' + sFormButton + '</p></div>\n'; sEnd += ' </div>\n' \ '</form>\n'; return (sTop, sEnd);
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 _generatePage(self): """ Generates the page using _sTemplate, _sPageTitle, _aaoMenus, and _sPageBody. """ assert self._sRedirectTo is None; # # Build the replacement string dictionary. # # Provide basic auth log out for browsers that supports it. sUserAgent = self._oSrvGlue.getUserAgent(); if (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Firefox') > 0) \ or False: # Log in as the logout user in the same realm, the browser forgets # the old login and the job is done. (see apache sample conf) sLogOut = ' (<a href="%s://logout:logout@%s%slogout.py">logout</a>)' \ % (self._oSrvGlue.getUrlScheme(), self._oSrvGlue.getUrlNetLoc(), self._oSrvGlue.getUrlBasePath()); elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Safari') > 0) \ or False: # For a 401, causing the browser to forget the old login. Works # with safari as well as the two above. Since safari consider the # above method a phishing attempt and displays a warning to that # effect, which when taken seriously aborts the logout, this method # is preferable, even if it throws logon boxes in the user's face # till he/she/it hits escape, because it always works. sLogOut = ' (<a href="logout2.py">logout</a>)' elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('MSIE') > 0) \ or (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Chrome') > 0) \ or False: ## There doesn't seem to be any way to make IE really log out # without using a cookie and systematically 401 accesses based on # some logout state associated with it. Not sure how secure that # can be made and we really want to avoid cookies. So, perhaps, # just avoid IE for now. :-) ## Chrome/21.0 doesn't want to log out either. sLogOut = '' else: sLogOut = '' # Prep Menus. (sTopMenuItems, sSideMenuItems) = self._generateMenus(); # The dictionary (max variable length is 28 chars (see further down)). dReplacements = { '@@PAGE_TITLE@@': self._sPageTitle, '@@LOG_OUT@@': sLogOut, '@@TESTMANAGER_VERSION@@': config.g_ksVersion, '@@TESTMANAGER_REVISION@@': config.g_ksRevision, '@@BASE_URL@@': self._oSrvGlue.getBaseUrl(), '@@TOP_MENU_ITEMS@@': sTopMenuItems, '@@SIDE_MENU_ITEMS@@': sSideMenuItems, '@@SIDE_FILTER_CONTROL@@': self._sPageFilter, '@@SIDE_MENU_FORM_ATTRS@@': '', '@@PAGE_BODY@@': self._sPageBody, '@@DEBUG@@': '', }; # Side menu form attributes. if self._dSideMenuFormAttrs: dReplacements['@@SIDE_MENU_FORM_ATTRS@@'] = ' '.join(['%s="%s"' % (sKey, webutils.escapeAttr(sValue)) for sKey, sValue in self._dSideMenuFormAttrs.items()]); # Special current user handling. if self._oCurUser is not None: dReplacements['@@USER_NAME@@'] = self._oCurUser.sUsername; else: dReplacements['@@USER_NAME@@'] = 'unauthorized user "' + self._oSrvGlue.getLoginName() + '"'; # Prep debug section. if self._sDebug == '': if config.g_kfWebUiSqlTrace or self._fDbgSqlTrace or self._fDbgSqlExplain: self._sDebug = '<h3>Processed in %s ns.</h3>\n%s\n' \ % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,), self._oDb.debugHtmlReport(self._oSrvGlue.tsStart)); elif config.g_kfWebUiProcessedIn: self._sDebug = '<h3>Processed in %s ns.</h3>\n' \ % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,), ); if config.g_kfWebUiDebugPanel: self._sDebug += self._debugRenderPanel(); if self._sDebug != '': dReplacements['@@DEBUG@@'] = u'<div id="debug"><br><br><hr/>' \ + (unicode(self._sDebug, errors='ignore') if isinstance(self._sDebug, str) else self._sDebug) \ + u'</div>\n'; # # Load the template. # oFile = open(os.path.join(self._oSrvGlue.pathTmWebUI(), self._sTemplate)); sTmpl = oFile.read(); oFile.close(); # # Process the template, outputting each part we process. # offStart = 0; offCur = 0; while offCur < len(sTmpl): # Look for a replacement variable. offAtAt = sTmpl.find('@@', offCur); if offAtAt < 0: break; offCur = offAtAt + 2; if sTmpl[offCur] not in string.ascii_uppercase: continue; offEnd = sTmpl.find('@@', offCur, offCur+28); if offEnd <= 0: continue; offCur = offEnd; sReplacement = sTmpl[offAtAt:offEnd+2]; if sReplacement in dReplacements: # Got a match! Write out the previous chunk followed by the replacement text. if offStart < offAtAt: self._oSrvGlue.write(sTmpl[offStart:offAtAt]); self._oSrvGlue.write(dReplacements[sReplacement]); # Advance past the replacement point in the template. offCur += 2; offStart = offCur; else: assert False, 'Unknown replacement "%s" at offset %s in %s' % (sReplacement, offAtAt, self._sTemplate ); # The final chunk. if offStart < len(sTmpl): self._oSrvGlue.write(sTmpl[offStart:]); return True;
def _generatePage(self): """ Generates the page using _sTemplate, _sPageTitle, _aaoMenus, and _sPageBody. """ assert self._sRedirectTo is None; # # Build the replacement string dictionary. # # Provide basic auth log out for browsers that supports it. sUserAgent = self._oSrvGlue.getUserAgent(); if (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Firefox') > 0) \ or False: # Log in as the logout user in the same realm, the browser forgets # the old login and the job is done. (see apache sample conf) sLogOut = ' (<a href="%s://logout:logout@%s%slogout.py">logout</a>)' \ % (self._oSrvGlue.getUrlScheme(), self._oSrvGlue.getUrlNetLoc(), self._oSrvGlue.getUrlBasePath()); elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Safari') > 0) \ or False: # For a 401, causing the browser to forget the old login. Works # with safari as well as the two above. Since safari consider the # above method a phishing attempt and displays a warning to that # effect, which when taken seriously aborts the logout, this method # is preferable, even if it throws logon boxes in the user's face # till he/she/it hits escape, because it always works. sLogOut = ' (<a href="logout2.py">logout</a>)' elif (sUserAgent.startswith('Mozilla/') and sUserAgent.find('MSIE') > 0) \ or (sUserAgent.startswith('Mozilla/') and sUserAgent.find('Chrome') > 0) \ or False: ## There doesn't seem to be any way to make IE really log out # without using a cookie and systematically 401 accesses based on # some logout state associated with it. Not sure how secure that # can be made and we really want to avoid cookies. So, perhaps, # just avoid IE for now. :-) ## Chrome/21.0 doesn't want to log out either. sLogOut = '' else: sLogOut = '' # Prep Menus. (sTopMenuItems, sSideMenuItems) = self._generateMenus(); # The dictionary (max variable length is 28 chars (see further down)). dReplacements = { '@@PAGE_TITLE@@': self._sPageTitle, '@@LOG_OUT@@': sLogOut, '@@TESTMANAGER_VERSION@@': config.g_ksVersion, '@@TESTMANAGER_REVISION@@': config.g_ksRevision, '@@BASE_URL@@': self._oSrvGlue.getBaseUrl(), '@@TOP_MENU_ITEMS@@': sTopMenuItems, '@@SIDE_MENU_ITEMS@@': sSideMenuItems, '@@SIDE_FILTER_CONTROL@@': self._sPageFilter, '@@SIDE_MENU_FORM_ATTRS@@': '', '@@PAGE_BODY@@': self._sPageBody, '@@DEBUG@@': '', }; # Side menu form attributes. if self._dSideMenuFormAttrs: dReplacements['@@SIDE_MENU_FORM_ATTRS@@'] = ' '.join(['%s="%s"' % (sKey, webutils.escapeAttr(sValue)) for sKey, sValue in self._dSideMenuFormAttrs.items()]); # Special current user handling. if self._oCurUser is not None: dReplacements['@@USER_NAME@@'] = self._oCurUser.sUsername; else: dReplacements['@@USER_NAME@@'] = 'unauthorized user "' + self._oSrvGlue.getLoginName() + '"'; # Prep debug section. if self._sDebug == '': if config.g_kfWebUiSqlTrace or self._fDbgSqlTrace or self._fDbgSqlExplain: self._sDebug = '<h3>Processed in %s ns.</h3>\n%s\n' \ % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,), self._oDb.debugHtmlReport(self._oSrvGlue.tsStart)); elif config.g_kfWebUiProcessedIn: self._sDebug = '<h3>Processed in %s ns.</h3>\n' \ % ( utils.formatNumber(utils.timestampNano() - self._oSrvGlue.tsStart,), ); if config.g_kfWebUiDebugPanel: self._sDebug += self._debugRenderPanel(); if self._sDebug != '': dReplacements['@@DEBUG@@'] = u'<div id="debug"><br><br><hr/>' \ + (utils.toUnicode(self._sDebug, errors='ignore') if isinstance(self._sDebug, str) else self._sDebug) \ + u'</div>\n'; # # Load the template. # oFile = open(os.path.join(self._oSrvGlue.pathTmWebUI(), self._sTemplate)); sTmpl = oFile.read(); oFile.close(); # # Process the template, outputting each part we process. # offStart = 0; offCur = 0; while offCur < len(sTmpl): # Look for a replacement variable. offAtAt = sTmpl.find('@@', offCur); if offAtAt < 0: break; offCur = offAtAt + 2; if sTmpl[offCur] not in string.ascii_uppercase: continue; offEnd = sTmpl.find('@@', offCur, offCur+28); if offEnd <= 0: continue; offCur = offEnd; sReplacement = sTmpl[offAtAt:offEnd+2]; if sReplacement in dReplacements: # Got a match! Write out the previous chunk followed by the replacement text. if offStart < offAtAt: self._oSrvGlue.write(sTmpl[offStart:offAtAt]); self._oSrvGlue.write(dReplacements[sReplacement]); # Advance past the replacement point in the template. offCur += 2; offStart = offCur; else: assert False, 'Unknown replacement "%s" at offset %s in %s' % (sReplacement, offAtAt, self._sTemplate ); # The final chunk. if offStart < len(sTmpl): self._oSrvGlue.write(sTmpl[offStart:]); return True;
def addListOfTestCaseArgs(self, sName, aoVariations, sLabel): # pylint: disable=R0915 """ Adds a list of test case argument variations to the form. @param sName Name of HTML form element @param aoVariations List of TestCaseArgsData instances. @param sLabel Label of HTML form element """ self._addLabel(sName, sLabel); sTableId = 'TestArgsExtendingListRoot'; fReadOnly = self._fReadOnly; ## @todo argument? sReadOnlyAttr = ' readonly class="tmform-input-readonly"' if fReadOnly else ''; sHtml = '<li>\n' # # Define javascript function for extending the list of test case # variations. Doing it here so we can use the python constants. This # also permits multiple argument lists on one page should that ever be # required... # if not fReadOnly: sHtml += '<script type="text/javascript">\n' sHtml += '\n'; sHtml += 'g_%s_aItems = { %s };\n' % (sName, ', '.join(('%s: 1' % (i,)) for i in range(len(aoVariations))),); sHtml += 'g_%s_cItems = %s;\n' % (sName, len(aoVariations),); sHtml += 'g_%s_iIdMod = %s;\n' % (sName, len(aoVariations) + 32); sHtml += '\n'; sHtml += 'function %s_removeEntry(sId)\n' % (sName,); sHtml += '{\n'; sHtml += ' if (g_%s_cItems > 1)\n' % (sName,); sHtml += ' {\n'; sHtml += ' g_%s_cItems--;\n' % (sName,); sHtml += ' delete g_%s_aItems[sId];\n' % (sName,); sHtml += ' setElementValueToKeyList(\'%s\', g_%s_aItems);\n' % (sName, sName); sHtml += '\n'; for iInput in range(8): sHtml += ' removeHtmlNode(\'%s[\' + sId + \'][%s]\');\n' % (sName, iInput,); sHtml += ' }\n'; sHtml += '}\n'; sHtml += '\n'; sHtml += 'function %s_extendListEx(cGangMembers, cSecTimeout, sArgs, sTestBoxReqExpr, sBuildReqExpr)\n' % (sName,); sHtml += '{\n'; sHtml += ' var oElement = document.getElementById(\'%s\');\n' % (sTableId,); sHtml += ' var oTBody = document.createElement(\'tbody\');\n'; sHtml += ' var sHtml = \'\';\n'; sHtml += ' var sId;\n'; sHtml += '\n'; sHtml += ' g_%s_iIdMod += 1;\n' % (sName,); sHtml += ' sId = g_%s_iIdMod.toString();\n' % (sName,); oVarDefaults = TestCaseArgsData(); oVarDefaults.convertToParamNull(); sHtml += '\n'; sHtml += ' sHtml += \'<tr class="tmform-testcasevars-first-row">\';\n'; sHtml += ' sHtml += \' <td>Gang Members:</td>\';\n'; sHtml += ' sHtml += \' <td class="tmform-field-tiny-int">' \ '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][0]" value="\' + cGangMembers + \'"></td>\';\n' \ % (sName, TestCaseArgsData.ksParam_cGangMembers, sName,); sHtml += ' sHtml += \' <td>Timeout:</td>\';\n'; sHtml += ' sHtml += \' <td class="tmform-field-int">' \ '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][1]" value="\'+ cSecTimeout + \'"></td>\';\n' \ % (sName, TestCaseArgsData.ksParam_cSecTimeout, sName,); sHtml += ' sHtml += \' <td><a href="#" onclick="%s_removeEntry(\\\'\' + sId + \'\\\');"> Remove</a></td>\';\n' \ % (sName, ); sHtml += ' sHtml += \' <td></td>\';\n'; sHtml += ' sHtml += \'</tr>\';\n' sHtml += '\n'; sHtml += ' sHtml += \'<tr class="tmform-testcasevars-inner-row">\';\n'; sHtml += ' sHtml += \' <td>Arguments:</td>\';\n'; sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sArgs + \'"></td>\';\n' \ % (sName, TestCaseArgsData.ksParam_sArgs, sName,); sHtml += ' sHtml += \' <td></td>\';\n'; sHtml += ' sHtml += \'</tr>\';\n' sHtml += '\n'; sHtml += ' sHtml += \'<tr class="tmform-testcasevars-inner-row">\';\n'; sHtml += ' sHtml += \' <td>TestBox Reqs:</td>\';\n'; sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sTestBoxReqExpr' \ ' + \'"></td>\';\n' \ % (sName, TestCaseArgsData.ksParam_sTestBoxReqExpr, sName,); sHtml += ' sHtml += \' <td></td>\';\n'; sHtml += ' sHtml += \'</tr>\';\n' sHtml += '\n'; sHtml += ' sHtml += \'<tr class="tmform-testcasevars-final-row">\';\n'; sHtml += ' sHtml += \' <td>Build Reqs:</td>\';\n'; sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sBuildReqExpr + \'"></td>\';\n' \ % (sName, TestCaseArgsData.ksParam_sBuildReqExpr, sName,); sHtml += ' sHtml += \' <td></td>\';\n'; sHtml += ' sHtml += \'</tr>\';\n' sHtml += '\n'; sHtml += ' oTBody.id = \'%s[\' + sId + \'][6]\';\n' % (sName,); sHtml += ' oTBody.innerHTML = sHtml;\n'; sHtml += '\n'; sHtml += ' oElement.appendChild(oTBody);\n'; sHtml += '\n'; sHtml += ' g_%s_aItems[sId] = 1;\n' % (sName,); sHtml += ' g_%s_cItems++;\n' % (sName,); sHtml += ' setElementValueToKeyList(\'%s\', g_%s_aItems);\n' % (sName, sName); sHtml += '}\n'; sHtml += 'function %s_extendList()\n' % (sName,); sHtml += '{\n'; sHtml += ' %s_extendListEx("%s", "%s", "%s", "%s", "%s");\n' % (sName, escapeAttr(str(oVarDefaults.cGangMembers)), escapeAttr(str(oVarDefaults.cSecTimeout)), escapeAttr(oVarDefaults.sArgs), escapeAttr(oVarDefaults.sTestBoxReqExpr), escapeAttr(oVarDefaults.sBuildReqExpr), ); sHtml += '}\n'; if config.g_kfVBoxSpecific: sSecTimeoutDef = escapeAttr(str(oVarDefaults.cSecTimeout)); sHtml += 'function vbox_%s_add_uni()\n' % (sName,); sHtml += '{\n'; sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes raw", ' \ ' "", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt", ' \ ' "fCpuHwVirt is True", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt-np", ' \ ' "fCpuNestedPaging is True", "");\n' % (sName, sSecTimeoutDef); sHtml += '}\n'; sHtml += 'function vbox_%s_add_uni_amd64()\n' % (sName,); sHtml += '{\n'; sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt", ' \ ' "fCpuHwVirt is True", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt-np", ' \ ' "fCpuNestedPaging is True", "");\n' % (sName, sSecTimeoutDef); sHtml += '}\n'; sHtml += 'function vbox_%s_add_smp()\n' % (sName,); sHtml += '{\n'; sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 2 --virt-modes hwvirt",' \ ' "fCpuHwVirt is True and cCpus >= 2", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 2 --virt-modes hwvirt-np",' \ ' "fCpuNestedPaging is True and cCpus >= 2", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 3 --virt-modes hwvirt",' \ ' "fCpuHwVirt is True and cCpus >= 3", "");\n' % (sName, sSecTimeoutDef); sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 4 --virt-modes hwvirt-np ",' \ ' "fCpuNestedPaging is True and cCpus >= 4", "");\n' % (sName, sSecTimeoutDef); #sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 6 --virt-modes hwvirt",' \ # ' "fCpuHwVirt is True and cCpus >= 6", "");\n' % (sName, sSecTimeoutDef); #sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 8 --virt-modes hwvirt-np",' \ # ' "fCpuNestedPaging is True and cCpus >= 8", "");\n' % (sName, sSecTimeoutDef); sHtml += '}\n'; sHtml += '</script>\n'; # # List current entries. # sHtml += '<input type="hidden" name="%s" id="%s" value="%s">\n' \ % (sName, sName, ','.join(str(i) for i in range(len(aoVariations))), ); sHtml += ' <table id="%s" class="tmform-testcasevars">\n' % (sTableId,) if not fReadOnly: sHtml += ' <caption>\n' \ ' <a href="#" onClick="%s_extendList()">Add</a>\n' % (sName,); if config.g_kfVBoxSpecific: sHtml += ' [<a href="#" onClick="vbox_%s_add_uni()">Single CPU Variations</a>\n' % (sName,); sHtml += ' <a href="#" onClick="vbox_%s_add_uni_amd64()">amd64</a>]\n' % (sName,); sHtml += ' [<a href="#" onClick="vbox_%s_add_smp()">SMP Variations</a>]\n' % (sName,); sHtml += ' </caption>\n'; dSubErrors = {}; if sName in self._dErrors and isinstance(self._dErrors[sName], dict): dSubErrors = self._dErrors[sName]; for iVar in range(len(aoVariations)): oVar = copy.copy(aoVariations[iVar]); oVar.convertToParamNull(); sHtml += '<tbody id="%s[%s][6]">\n' % (sName, iVar,) sHtml += ' <tr class="tmform-testcasevars-first-row">\n' \ ' <td>Gang Members:</td>' \ ' <td class="tmform-field-tiny-int"><input name="%s[%s][%s]" id="%s[%s][1]" value="%s"%s></td>\n' \ ' <td>Timeout:</td>' \ ' <td class="tmform-field-int"><input name="%s[%s][%s]" id="%s[%s][2]" value="%s"%s></td>\n' \ % ( sName, iVar, TestCaseArgsData.ksParam_cGangMembers, sName, iVar, oVar.cGangMembers, sReadOnlyAttr, sName, iVar, TestCaseArgsData.ksParam_cSecTimeout, sName, iVar, utils.formatIntervalSeconds2(oVar.cSecTimeout), sReadOnlyAttr, ); if not fReadOnly: sHtml += ' <td><a href="#" onclick="%s_removeEntry(\'%s\');">Remove</a></td>\n' \ % (sName, iVar); else: sHtml += ' <td></td>\n'; sHtml += ' <td class="tmform-testcasevars-stupid-border-column"></td>\n' \ ' </tr>\n'; sHtml += ' <tr class="tmform-testcasevars-inner-row">\n' \ ' <td>Arguments:</td>' \ ' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[%s][%s]" id="%s[%s][3]" value="%s"%s></td>\n' \ ' <td></td>\n' \ ' </tr>\n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sArgs, sName, iVar, escapeAttr(oVar.sArgs), sReadOnlyAttr) sHtml += ' <tr class="tmform-testcasevars-inner-row">\n' \ ' <td>TestBox Reqs:</td>' \ ' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[%s][%s]" id="%s[%s][4]" value="%s"%s></td>\n' \ ' <td></td>\n' \ ' </tr>\n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sTestBoxReqExpr, sName, iVar, escapeAttr(oVar.sTestBoxReqExpr), sReadOnlyAttr) sHtml += ' <tr class="tmform-testcasevars-final-row">\n' \ ' <td>Build Reqs:</td>' \ ' <td class="tmform-field-wide100" colspan="4">' \ '<input name="%s[%s][%s]" id="%s[%s][5]" value="%s"%s></td>\n' \ ' <td></td>\n' \ ' </tr>\n' \ % ( sName, iVar, TestCaseArgsData.ksParam_sBuildReqExpr, sName, iVar, escapeAttr(oVar.sBuildReqExpr), sReadOnlyAttr) if iVar in dSubErrors: sHtml += ' <tr><td colspan="4"><p align="left" class="tmform-error-desc">%s</p></td></tr>\n' \ % (self._escapeErrorText(dSubErrors[iVar]),); sHtml += '</tbody>\n'; sHtml += ' </table>\n' sHtml += '</li>\n' return self._add(sHtml)
def __init__(self, sSpanClass, sText): WuiRawHtml.__init__( self, u'<span class="%s">%s</span>' % (webutils.escapeAttr(sSpanClass), webutils.escapeElem(sText)) )