VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testmanager/webui/wuihlpform.py@ 61217

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.8 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: wuihlpform.py 61217 2016-05-26 20:04:05Z vboxsync $
3
4"""
5Test Manager Web-UI - Form Helpers.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2015 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 61217 $"
30
31# Standard python imports.
32import copy;
33
34# Validation Kit imports.
35from common import utils;
36from common.webutils import escapeAttr, escapeElem;
37from testmanager import config;
38from testmanager.core.schedgroup import SchedGroupMemberData, SchedGroupDataEx;
39from testmanager.core.testcaseargs import TestCaseArgsData;
40from testmanager.core.testgroup import TestGroupMemberData, TestGroupDataEx;
41
42
43class WuiHlpForm(object):
44 """
45 Helper for constructing a form.
46 """
47
48 ksItemsList = 'ksItemsList'
49
50 ksOnSubmit_AddReturnToFieldWithCurrentUrl = '+AddReturnToFieldWithCurrentUrl+';
51
52 def __init__(self, sId, sAction, dErrors = None, fReadOnly = False, sOnSubmit = None):
53 self._fFinalized = False;
54 self._fReadOnly = fReadOnly;
55 self._dErrors = dErrors if dErrors is not None else dict();
56
57 if sOnSubmit == self.ksOnSubmit_AddReturnToFieldWithCurrentUrl:
58 sOnSubmit = 'return addRedirectToInputFieldWithCurrentUrl(this)';
59 if sOnSubmit is None: sOnSubmit = u'';
60 else: sOnSubmit = u' onsubmit=\"%s\"' % (escapeAttr(sOnSubmit),);
61
62 self._sBody = u'\n' \
63 u'<div id="%s" class="tmform">\n' \
64 u' <form action="%s" method="post"%s>\n' \
65 u' <ul>\n' \
66 % (sId, sAction, sOnSubmit);
67
68 def _add(self, sText):
69 """Internal worker for appending text to the body."""
70 assert not self._fFinalized;
71 if not self._fFinalized:
72 self._sBody += unicode(sText, errors='ignore') if isinstance(sText, str) else sText;
73 return True;
74 return False;
75
76 def _escapeErrorText(self, sText):
77 """Escapes error text, preserving some predefined HTML tags."""
78 if sText.find('<br>') >= 0:
79 asParts = sText.split('<br>');
80 for i, _ in enumerate(asParts):
81 asParts[i] = escapeElem(asParts[i].strip());
82 sText = '<br>\n'.join(asParts);
83 else:
84 sText = escapeElem(sText);
85 return sText;
86
87 def _addLabel(self, sName, sLabel, sDivSubClass = 'normal'):
88 """Internal worker for adding a label."""
89 if sName in self._dErrors:
90 sError = self._dErrors[sName];
91 if utils.isString(sError): # List error trick (it's an associative array).
92 return self._add(' <li>\n'
93 ' <div class="tmform-field"><div class="tmform-field-%s">\n'
94 ' <label for="%s" class="tmform-error-label">%s\n'
95 ' <span class="tmform-error-desc">%s</span>\n'
96 ' </label>\n'
97 % (escapeAttr(sDivSubClass), escapeAttr(sName), escapeElem(sLabel),
98 self._escapeErrorText(sError), ) );
99 return self._add(' <li>\n'
100 ' <div class="tmform-field"><div class="tmform-field-%s">\n'
101 ' <label for="%s">%s</label>\n'
102 % (escapeAttr(sDivSubClass), escapeAttr(sName), escapeElem(sLabel)) );
103
104
105 def finalize(self):
106 """
107 Finalizes the form and returns the body.
108 """
109 if not self._fFinalized:
110 self._add(' </ul>\n'
111 ' </form>\n'
112 '</div>\n'
113 '<div class="clear"></div>\n'
114 );
115 return self._sBody;
116
117 def addTextHidden(self, sName, sValue, sExtraAttribs = ''):
118 """Adds a hidden text input."""
119 return self._add(' <div class="tmform-field-hidden">\n'
120 ' <input name="%s" id="%s" type="text" hidden%s value="%s" class="tmform-hidden">\n'
121 ' </div>\n'
122 ' </li>\n'
123 % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)) ));
124 #
125 # Non-input stuff.
126 #
127 def addNonText(self, sValue, sLabel, sPostHtml = ''):
128 """Adds a read-only text input."""
129 self._addLabel('non-text', sLabel, 'string');
130 if sValue is None: sValue = '';
131 return self._add(' <p>%s</p>%s\n'
132 ' </div></div>\n'
133 ' </li>\n'
134 % (escapeElem(str(sValue)), sPostHtml ));
135
136
137 #
138 # Text input fields.
139 #
140 def addText(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = '', sPostHtml = ''):
141 """Adds a text input."""
142 if self._fReadOnly:
143 return self.addTextRO(sName, sValue, sLabel, sSubClass, sExtraAttribs);
144 if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass);
145 self._addLabel(sName, sLabel, sSubClass);
146 if sValue is None: sValue = '';
147 return self._add(' <input name="%s" id="%s" type="text"%s value="%s">%s\n'
148 ' </div></div>\n'
149 ' </li>\n'
150 % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sValue), sPostHtml ));
151
152 def addTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = '', sPostHtml = ''):
153 """Adds a read-only text input."""
154 if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp', 'wide'): raise Exception(sSubClass);
155 self._addLabel(sName, sLabel, sSubClass);
156 if sValue is None: sValue = '';
157 return self._add(' <input name="%s" id="%s" type="text" readonly%s value="%s" class="tmform-input-readonly">%s\n'
158 ' </div></div>\n'
159 ' </li>\n'
160 % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(str(sValue)), sPostHtml ));
161
162 def addWideText(self, sName, sValue, sLabel, sExtraAttribs = ''):
163 """Adds a wide text input."""
164 return self.addText(sName, sValue, sLabel, 'wide', sExtraAttribs);
165
166 def addWideTextRO(self, sName, sValue, sLabel, sExtraAttribs = ''):
167 """Adds a wide read-only text input."""
168 return self.addTextRO(sName, sValue, sLabel, 'wide', sExtraAttribs);
169
170
171 def addMultilineText(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = ''):
172 """Adds a multiline text input."""
173 if self._fReadOnly:
174 return self.addMultilineTextRO(sName, sValue, sLabel, sSubClass, sExtraAttribs);
175 if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp'): raise Exception(sSubClass)
176 self._addLabel(sName, sLabel, sSubClass)
177 if sValue is None: sValue = '';
178 sNewValue = str(sValue) if not isinstance(sValue, list) else '\n'.join(sValue)
179 return self._add(' <textarea name="%s" id="%s" %s>%s</textarea>\n'
180 ' </div></div>\n'
181 ' </li>\n'
182 % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue)))
183
184 def addMultilineTextRO(self, sName, sValue, sLabel, sSubClass = 'string', sExtraAttribs = ''):
185 """Adds a multiline read-only text input."""
186 if sSubClass not in ('int', 'long', 'string', 'uuid', 'timestamp'): raise Exception(sSubClass)
187 self._addLabel(sName, sLabel, sSubClass)
188 if sValue is None: sValue = '';
189 sNewValue = str(sValue) if not isinstance(sValue, list) else '\n'.join(sValue)
190 return self._add(' <textarea name="%s" id="%s" readonly %s>%s</textarea>\n'
191 ' </div></div>\n'
192 ' </li>\n'
193 % ( escapeAttr(sName), escapeAttr(sName), sExtraAttribs, escapeElem(sNewValue)))
194
195 def addInt(self, sName, iValue, sLabel, sExtraAttribs = ''):
196 """Adds an integer input."""
197 return self.addText(sName, str(iValue), sLabel, 'int', sExtraAttribs);
198
199 def addIntRO(self, sName, iValue, sLabel, sExtraAttribs = ''):
200 """Adds an integer input."""
201 return self.addTextRO(sName, str(iValue), sLabel, 'int', sExtraAttribs);
202
203 def addLong(self, sName, lValue, sLabel, sExtraAttribs = ''):
204 """Adds a long input."""
205 return self.addText(sName, str(lValue), sLabel, 'long', sExtraAttribs);
206
207 def addLongRO(self, sName, lValue, sLabel, sExtraAttribs = ''):
208 """Adds a long input."""
209 return self.addTextRO(sName, str(lValue), sLabel, 'long', sExtraAttribs);
210
211 def addUuid(self, sName, uuidValue, sLabel, sExtraAttribs = ''):
212 """Adds an UUID input."""
213 return self.addText(sName, str(uuidValue), sLabel, 'uuid', sExtraAttribs);
214
215 def addUuidRO(self, sName, uuidValue, sLabel, sExtraAttribs = ''):
216 """Adds a read-only UUID input."""
217 return self.addTextRO(sName, str(uuidValue), sLabel, 'uuid', sExtraAttribs);
218
219 def addTimestampRO(self, sName, sTimestamp, sLabel, sExtraAttribs = ''):
220 """Adds a read-only database string timstamp input."""
221 return self.addTextRO(sName, sTimestamp, sLabel, 'timestamp', sExtraAttribs);
222
223
224 #
225 # Text areas.
226 #
227
228
229 #
230 # Combo boxes.
231 #
232 def addComboBox(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs = ''):
233 """Adds a combo box."""
234 if self._fReadOnly:
235 return self.addComboBoxRO(sName, sSelected, sLabel, aoOptions, sExtraAttribs);
236 self._addLabel(sName, sLabel, 'combobox');
237 self._add(' <select name="%s" id="%s" class="tmform-combobox"%s>\n'
238 % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs));
239 sSelected = str(sSelected);
240 for iValue, sText, _ in aoOptions:
241 sValue = str(iValue);
242 self._add(' <option value="%s"%s>%s</option>\n'
243 % (escapeAttr(sValue), ' selected' if sValue == sSelected else '',
244 escapeElem(sText)));
245 return self._add(' </select>\n'
246 ' </div></div>\n'
247 ' </li>\n'
248 );
249
250 def addComboBoxRO(self, sName, sSelected, sLabel, aoOptions, sExtraAttribs = ''):
251 """Adds a read-only combo box."""
252 self.addTextHidden(sName, sSelected);
253 self._addLabel(sName, sLabel, 'combobox-readonly');
254 self._add(' <select name="%s" id="%s" disabled class="tmform-combobox"%s>\n'
255 % (escapeAttr(sName), escapeAttr(sName), sExtraAttribs));
256 sSelected = str(sSelected);
257 for iValue, sText, _ in aoOptions:
258 sValue = str(iValue);
259 self._add(' <option value="%s"%s>%s</option>\n'
260 % (escapeAttr(sValue), ' selected' if sValue == sSelected else '',
261 escapeElem(sText)));
262 return self._add(' </select>\n'
263 ' </div></div>\n'
264 ' </li>\n'
265 );
266
267 #
268 # Check boxes.
269 #
270 @staticmethod
271 def _reinterpretBool(fValue):
272 """Reinterprets a value as a boolean type."""
273 if fValue is not type(True):
274 if fValue is None:
275 fValue = False;
276 elif str(fValue) in ('True', 'true', '1'):
277 fValue = True;
278 else:
279 fValue = False;
280 return fValue;
281
282 def addCheckBox(self, sName, fChecked, sLabel, sExtraAttribs = ''):
283 """Adds an check box."""
284 if self._fReadOnly:
285 return self.addCheckBoxRO(sName, fChecked, sLabel, sExtraAttribs);
286 self._addLabel(sName, sLabel, 'checkbox');
287 fChecked = self._reinterpretBool(fChecked);
288 return self._add(' <input name="%s" id="%s" type="checkbox"%s%s value="1" class="tmform-checkbox">\n'
289 ' </div></div>\n'
290 ' </li>\n'
291 % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs));
292
293 def addCheckBoxRO(self, sName, fChecked, sLabel, sExtraAttribs = ''):
294 """Adds an readonly check box."""
295 self._addLabel(sName, sLabel, 'checkbox');
296 fChecked = self._reinterpretBool(fChecked);
297 # Hack Alert! The onclick and onkeydown are for preventing editing and fake readonly/disabled.
298 return self._add(' <input name="%s" id="%s" type="checkbox"%s readonly%s value="1" class="readonly"\n'
299 ' onclick="return false" onkeydown="return false">\n'
300 ' </div></div>\n'
301 ' </li>\n'
302 % (escapeAttr(sName), escapeAttr(sName), ' checked' if fChecked else '', sExtraAttribs));
303
304 #
305 # List of items to check
306 #
307 def _addList(self, sName, aoRows, sLabel, fUseTable = False, sId = 'dummy', sExtraAttribs = ''):
308 """
309 Adds a list of items to check.
310
311 @param sName Name of HTML form element
312 @param aoRows List of [sValue, fChecked, sName] sub-arrays.
313 @param sLabel Label of HTML form element
314 """
315 fReadOnly = self._fReadOnly; ## @todo add this as a parameter.
316 if fReadOnly:
317 sExtraAttribs += ' readonly onclick="return false" onkeydown="return false"';
318
319 self._addLabel(sName, sLabel, 'list');
320 if len(aoRows) == 0:
321 return self._add('No items</div></div></li>')
322 sNameEscaped = escapeAttr(sName);
323
324 self._add(' <div class="tmform-checkboxes-container" id="%s">\n' % (escapeAttr(sId),));
325 if fUseTable:
326 self._add(' <table>\n');
327 for asRow in aoRows:
328 assert len(asRow) == 3; # Don't allow sloppy input data!
329 fChecked = self._reinterpretBool(asRow[1])
330 self._add(' <tr>\n'
331 ' <td><input type="checkbox" name="%s" value="%s"%s%s></td>\n'
332 ' <td>%s</td>\n'
333 ' </tr>\n'
334 % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs,
335 escapeElem(str(asRow[2])), ));
336 self._add(' </table>\n');
337 else:
338 for asRow in aoRows:
339 assert len(asRow) == 3; # Don't allow sloppy input data!
340 fChecked = self._reinterpretBool(asRow[1])
341 self._add(' <div class="tmform-checkbox-holder">'
342 '<input type="checkbox" name="%s" value="%s"%s%s> %s</input></div>\n'
343 % ( sNameEscaped, escapeAttr(str(asRow[0])), ' checked' if fChecked else '', sExtraAttribs,
344 escapeElem(str(asRow[2])),));
345 return self._add(' </div></div></div>\n'
346 ' </li>\n');
347
348
349 def addListOfOsArches(self, sName, aoOsArches, sLabel, sExtraAttribs = ''):
350 """
351 List of checkboxes for OS/ARCH selection.
352 asOsArches is a list of [sValue, fChecked, sName] sub-arrays.
353 """
354 return self._addList(sName, aoOsArches, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-os-arches',
355 sExtraAttribs = sExtraAttribs);
356
357 def addListOfTypes(self, sName, aoTypes, sLabel, sExtraAttribs = ''):
358 """
359 List of checkboxes for build type selection.
360 aoTypes is a list of [sValue, fChecked, sName] sub-arrays.
361 """
362 return self._addList(sName, aoTypes, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-build-types',
363 sExtraAttribs = sExtraAttribs);
364
365 def addListOfTestCases(self, sName, aoTestCases, sLabel, sExtraAttribs = ''):
366 """
367 List of checkboxes for test box (dependency) selection.
368 aoTestCases is a list of [sValue, fChecked, sName] sub-arrays.
369 """
370 return self._addList(sName, aoTestCases, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-testcases',
371 sExtraAttribs = sExtraAttribs);
372
373 def addListOfResources(self, sName, aoTestCases, sLabel, sExtraAttribs = ''):
374 """
375 List of checkboxes for resource selection.
376 aoTestCases is a list of [sValue, fChecked, sName] sub-arrays.
377 """
378 return self._addList(sName, aoTestCases, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-resources',
379 sExtraAttribs = sExtraAttribs);
380
381 def addListOfTestGroups(self, sName, aoTestGroups, sLabel, sExtraAttribs = ''):
382 """
383 List of checkboxes for test group selection.
384 aoTestGroups is a list of [sValue, fChecked, sName] sub-arrays.
385 """
386 return self._addList(sName, aoTestGroups, sLabel, fUseTable = False, sId = 'tmform-checkbox-list-testgroups',
387 sExtraAttribs = sExtraAttribs);
388
389 def addListOfTestCaseArgs(self, sName, aoVariations, sLabel): # pylint: disable=R0915
390 """
391 Adds a list of test case argument variations to the form.
392
393 @param sName Name of HTML form element
394 @param aoVariations List of TestCaseArgsData instances.
395 @param sLabel Label of HTML form element
396 """
397 self._addLabel(sName, sLabel);
398
399 sTableId = 'TestArgsExtendingListRoot';
400 fReadOnly = self._fReadOnly; ## @todo argument?
401 sReadOnlyAttr = ' readonly class="tmform-input-readonly"' if fReadOnly else '';
402
403 sHtml = '<li>\n'
404
405 #
406 # Define javascript function for extending the list of test case
407 # variations. Doing it here so we can use the python constants. This
408 # also permits multiple argument lists on one page should that ever be
409 # required...
410 #
411 if not fReadOnly:
412 sHtml += '<script type="text/javascript">\n'
413 sHtml += '\n';
414 sHtml += 'g_%s_aItems = { %s };\n' % (sName, ', '.join(('%s: 1' % (i,)) for i in range(len(aoVariations))),);
415 sHtml += 'g_%s_cItems = %s;\n' % (sName, len(aoVariations),);
416 sHtml += 'g_%s_iIdMod = %s;\n' % (sName, len(aoVariations) + 32);
417 sHtml += '\n';
418 sHtml += 'function %s_removeEntry(sId)\n' % (sName,);
419 sHtml += '{\n';
420 sHtml += ' if (g_%s_cItems > 1)\n' % (sName,);
421 sHtml += ' {\n';
422 sHtml += ' g_%s_cItems--;\n' % (sName,);
423 sHtml += ' delete g_%s_aItems[sId];\n' % (sName,);
424 sHtml += ' setElementValueToKeyList(\'%s\', g_%s_aItems);\n' % (sName, sName);
425 sHtml += '\n';
426 for iInput in range(8):
427 sHtml += ' removeHtmlNode(\'%s[\' + sId + \'][%s]\');\n' % (sName, iInput,);
428 sHtml += ' }\n';
429 sHtml += '}\n';
430 sHtml += '\n';
431 sHtml += 'function %s_extendListEx(cGangMembers, cSecTimeout, sArgs, sTestBoxReqExpr, sBuildReqExpr)\n' % (sName,);
432 sHtml += '{\n';
433 sHtml += ' var oElement = document.getElementById(\'%s\');\n' % (sTableId,);
434 sHtml += ' var oTBody = document.createElement(\'tbody\');\n';
435 sHtml += ' var sHtml = \'\';\n';
436 sHtml += ' var sId;\n';
437 sHtml += '\n';
438 sHtml += ' g_%s_iIdMod += 1;\n' % (sName,);
439 sHtml += ' sId = g_%s_iIdMod.toString();\n' % (sName,);
440
441 oVarDefaults = TestCaseArgsData();
442 oVarDefaults.convertToParamNull();
443 sHtml += '\n';
444 sHtml += ' sHtml += \'<tr class="tmform-testcasevars-first-row">\';\n';
445 sHtml += ' sHtml += \' <td>Gang Members:</td>\';\n';
446 sHtml += ' sHtml += \' <td class="tmform-field-tiny-int">' \
447 '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][0]" value="\' + cGangMembers + \'"></td>\';\n' \
448 % (sName, TestCaseArgsData.ksParam_cGangMembers, sName,);
449 sHtml += ' sHtml += \' <td>Timeout:</td>\';\n';
450 sHtml += ' sHtml += \' <td class="tmform-field-int">' \
451 '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][1]" value="\'+ cSecTimeout + \'"></td>\';\n' \
452 % (sName, TestCaseArgsData.ksParam_cSecTimeout, sName,);
453 sHtml += ' sHtml += \' <td><a href="#" onclick="%s_removeEntry(\\\'\' + sId + \'\\\');"> Remove</a></td>\';\n' \
454 % (sName, );
455 sHtml += ' sHtml += \' <td></td>\';\n';
456 sHtml += ' sHtml += \'</tr>\';\n'
457 sHtml += '\n';
458 sHtml += ' sHtml += \'<tr class="tmform-testcasevars-inner-row">\';\n';
459 sHtml += ' sHtml += \' <td>Arguments:</td>\';\n';
460 sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \
461 '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sArgs + \'"></td>\';\n' \
462 % (sName, TestCaseArgsData.ksParam_sArgs, sName,);
463 sHtml += ' sHtml += \' <td></td>\';\n';
464 sHtml += ' sHtml += \'</tr>\';\n'
465 sHtml += '\n';
466 sHtml += ' sHtml += \'<tr class="tmform-testcasevars-inner-row">\';\n';
467 sHtml += ' sHtml += \' <td>TestBox Reqs:</td>\';\n';
468 sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \
469 '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sTestBoxReqExpr' \
470 ' + \'"></td>\';\n' \
471 % (sName, TestCaseArgsData.ksParam_sTestBoxReqExpr, sName,);
472 sHtml += ' sHtml += \' <td></td>\';\n';
473 sHtml += ' sHtml += \'</tr>\';\n'
474 sHtml += '\n';
475 sHtml += ' sHtml += \'<tr class="tmform-testcasevars-final-row">\';\n';
476 sHtml += ' sHtml += \' <td>Build Reqs:</td>\';\n';
477 sHtml += ' sHtml += \' <td class="tmform-field-wide100" colspan="4">' \
478 '<input name="%s[\' + sId + \'][%s]" id="%s[\' + sId + \'][2]" value="\' + sBuildReqExpr + \'"></td>\';\n' \
479 % (sName, TestCaseArgsData.ksParam_sBuildReqExpr, sName,);
480 sHtml += ' sHtml += \' <td></td>\';\n';
481 sHtml += ' sHtml += \'</tr>\';\n'
482 sHtml += '\n';
483 sHtml += ' oTBody.id = \'%s[\' + sId + \'][6]\';\n' % (sName,);
484 sHtml += ' oTBody.innerHTML = sHtml;\n';
485 sHtml += '\n';
486 sHtml += ' oElement.appendChild(oTBody);\n';
487 sHtml += '\n';
488 sHtml += ' g_%s_aItems[sId] = 1;\n' % (sName,);
489 sHtml += ' g_%s_cItems++;\n' % (sName,);
490 sHtml += ' setElementValueToKeyList(\'%s\', g_%s_aItems);\n' % (sName, sName);
491 sHtml += '}\n';
492 sHtml += 'function %s_extendList()\n' % (sName,);
493 sHtml += '{\n';
494 sHtml += ' %s_extendListEx("%s", "%s", "%s", "%s", "%s");\n' % (sName,
495 escapeAttr(str(oVarDefaults.cGangMembers)), escapeAttr(str(oVarDefaults.cSecTimeout)),
496 escapeAttr(oVarDefaults.sArgs), escapeAttr(oVarDefaults.sTestBoxReqExpr),
497 escapeAttr(oVarDefaults.sBuildReqExpr), );
498 sHtml += '}\n';
499 if config.g_kfVBoxSpecific:
500 sSecTimeoutDef = escapeAttr(str(oVarDefaults.cSecTimeout));
501 sHtml += 'function vbox_%s_add_uni()\n' % (sName,);
502 sHtml += '{\n';
503 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes raw", ' \
504 ' "", "");\n' % (sName, sSecTimeoutDef);
505 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt", ' \
506 ' "fCpuHwVirt is True", "");\n' % (sName, sSecTimeoutDef);
507 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt-np", ' \
508 ' "fCpuNestedPaging is True", "");\n' % (sName, sSecTimeoutDef);
509 sHtml += '}\n';
510 sHtml += 'function vbox_%s_add_uni_amd64()\n' % (sName,);
511 sHtml += '{\n';
512 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt", ' \
513 ' "fCpuHwVirt is True", "");\n' % (sName, sSecTimeoutDef);
514 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 1 --virt-modes hwvirt-np", ' \
515 ' "fCpuNestedPaging is True", "");\n' % (sName, sSecTimeoutDef);
516 sHtml += '}\n';
517 sHtml += 'function vbox_%s_add_smp()\n' % (sName,);
518 sHtml += '{\n';
519 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 2 --virt-modes hwvirt",' \
520 ' "fCpuHwVirt is True and cCpus >= 2", "");\n' % (sName, sSecTimeoutDef);
521 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 2 --virt-modes hwvirt-np",' \
522 ' "fCpuNestedPaging is True and cCpus >= 2", "");\n' % (sName, sSecTimeoutDef);
523 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 3 --virt-modes hwvirt",' \
524 ' "fCpuHwVirt is True and cCpus >= 3", "");\n' % (sName, sSecTimeoutDef);
525 sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 4 --virt-modes hwvirt-np ",' \
526 ' "fCpuNestedPaging is True and cCpus >= 4", "");\n' % (sName, sSecTimeoutDef);
527 #sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 6 --virt-modes hwvirt",' \
528 # ' "fCpuHwVirt is True and cCpus >= 6", "");\n' % (sName, sSecTimeoutDef);
529 #sHtml += ' %s_extendListEx("1", "%s", "--cpu-counts 8 --virt-modes hwvirt-np",' \
530 # ' "fCpuNestedPaging is True and cCpus >= 8", "");\n' % (sName, sSecTimeoutDef);
531 sHtml += '}\n';
532 sHtml += '</script>\n';
533
534
535 #
536 # List current entries.
537 #
538 sHtml += '<input type="hidden" name="%s" id="%s" value="%s">\n' \
539 % (sName, sName, ','.join(str(i) for i in range(len(aoVariations))), );
540 sHtml += ' <table id="%s" class="tmform-testcasevars">\n' % (sTableId,)
541 if not fReadOnly:
542 sHtml += ' <caption>\n' \
543 ' <a href="#" onClick="%s_extendList()">Add</a>\n' % (sName,);
544 if config.g_kfVBoxSpecific:
545 sHtml += ' [<a href="#" onClick="vbox_%s_add_uni()">Single CPU Variations</a>\n' % (sName,);
546 sHtml += ' <a href="#" onClick="vbox_%s_add_uni_amd64()">amd64</a>]\n' % (sName,);
547 sHtml += ' [<a href="#" onClick="vbox_%s_add_smp()">SMP Variations</a>]\n' % (sName,);
548 sHtml += ' </caption>\n';
549
550 dSubErrors = {};
551 if sName in self._dErrors and isinstance(self._dErrors[sName], dict):
552 dSubErrors = self._dErrors[sName];
553
554 for iVar, _ in enumerate(aoVariations):
555 oVar = copy.copy(aoVariations[iVar]);
556 oVar.convertToParamNull();
557
558 sHtml += '<tbody id="%s[%s][6]">\n' % (sName, iVar,)
559 sHtml += ' <tr class="tmform-testcasevars-first-row">\n' \
560 ' <td>Gang Members:</td>' \
561 ' <td class="tmform-field-tiny-int"><input name="%s[%s][%s]" id="%s[%s][1]" value="%s"%s></td>\n' \
562 ' <td>Timeout:</td>' \
563 ' <td class="tmform-field-int"><input name="%s[%s][%s]" id="%s[%s][2]" value="%s"%s></td>\n' \
564 % ( sName, iVar, TestCaseArgsData.ksParam_cGangMembers, sName, iVar, oVar.cGangMembers, sReadOnlyAttr,
565 sName, iVar, TestCaseArgsData.ksParam_cSecTimeout, sName, iVar,
566 utils.formatIntervalSeconds2(oVar.cSecTimeout), sReadOnlyAttr, );
567 if not fReadOnly:
568 sHtml += ' <td><a href="#" onclick="%s_removeEntry(\'%s\');">Remove</a></td>\n' \
569 % (sName, iVar);
570 else:
571 sHtml += ' <td></td>\n';
572 sHtml += ' <td class="tmform-testcasevars-stupid-border-column"></td>\n' \
573 ' </tr>\n';
574
575 sHtml += ' <tr class="tmform-testcasevars-inner-row">\n' \
576 ' <td>Arguments:</td>' \
577 ' <td class="tmform-field-wide100" colspan="4">' \
578 '<input name="%s[%s][%s]" id="%s[%s][3]" value="%s"%s></td>\n' \
579 ' <td></td>\n' \
580 ' </tr>\n' \
581 % ( sName, iVar, TestCaseArgsData.ksParam_sArgs, sName, iVar, escapeAttr(oVar.sArgs), sReadOnlyAttr)
582
583 sHtml += ' <tr class="tmform-testcasevars-inner-row">\n' \
584 ' <td>TestBox Reqs:</td>' \
585 ' <td class="tmform-field-wide100" colspan="4">' \
586 '<input name="%s[%s][%s]" id="%s[%s][4]" value="%s"%s></td>\n' \
587 ' <td></td>\n' \
588 ' </tr>\n' \
589 % ( sName, iVar, TestCaseArgsData.ksParam_sTestBoxReqExpr, sName, iVar,
590 escapeAttr(oVar.sTestBoxReqExpr), sReadOnlyAttr)
591
592 sHtml += ' <tr class="tmform-testcasevars-final-row">\n' \
593 ' <td>Build Reqs:</td>' \
594 ' <td class="tmform-field-wide100" colspan="4">' \
595 '<input name="%s[%s][%s]" id="%s[%s][5]" value="%s"%s></td>\n' \
596 ' <td></td>\n' \
597 ' </tr>\n' \
598 % ( sName, iVar, TestCaseArgsData.ksParam_sBuildReqExpr, sName, iVar,
599 escapeAttr(oVar.sBuildReqExpr), sReadOnlyAttr)
600
601
602 if iVar in dSubErrors:
603 sHtml += ' <tr><td colspan="4"><p align="left" class="tmform-error-desc">%s</p></td></tr>\n' \
604 % (self._escapeErrorText(dSubErrors[iVar]),);
605
606 sHtml += '</tbody>\n';
607 sHtml += ' </table>\n'
608 sHtml += '</li>\n'
609
610 return self._add(sHtml)
611
612 def addListOfTestGroupMembers(self, sName, aoTestGroupMembers, aoAllTestCases, sLabel, # pylint: disable=R0914
613 fReadOnly = True):
614 """
615 For WuiTestGroup.
616 """
617 assert len(aoTestGroupMembers) <= len(aoAllTestCases);
618 self._addLabel(sName, sLabel);
619 if len(aoAllTestCases) == 0:
620 return self._add('<li>No testcases available.</li>\n')
621
622 self._add('<input name="%s" type="hidden" value="%s">\n'
623 % ( TestGroupDataEx.ksParam_aidTestCases,
624 ','.join([str(oTestCase.idTestCase) for oTestCase in aoAllTestCases]), ));
625
626 self._add('<table class="tmformtbl">\n'
627 ' <thead>\n'
628 ' <tr>\n'
629 ' <th rowspan="2"></th>\n'
630 ' <th rowspan="2">Test Case</th>\n'
631 ' <th rowspan="2">All Vars</th>\n'
632 ' <th rowspan="2">Priority [0..31]</th>\n'
633 ' <th colspan="4" align="center">Variations</th>\n'
634 ' </tr>\n'
635 ' <tr>\n'
636 ' <th>Included</th>\n'
637 ' <th>Gang size</th>\n'
638 ' <th>Timeout</th>\n'
639 ' <th>Arguments</th>\n'
640 ' </tr>\n'
641 ' </thead>\n'
642 ' <tbody>\n'
643 );
644
645 if self._fReadOnly:
646 fReadOnly = True;
647 sCheckBoxAttr = ' readonly onclick="return false" onkeydown="return false"' if fReadOnly else '';
648
649 oDefMember = TestGroupMemberData();
650 aoTestGroupMembers = list(aoTestGroupMembers); # Copy it so we can pop.
651 for iTestCase, _ in enumerate(aoAllTestCases):
652 oTestCase = aoAllTestCases[iTestCase];
653
654 # Is it a member?
655 oMember = None;
656 for i, _ in enumerate(aoTestGroupMembers):
657 if aoTestGroupMembers[i].oTestCase.idTestCase == oTestCase.idTestCase:
658 oMember = aoTestGroupMembers.pop(i);
659 break;
660
661 # Start on the rows...
662 sPrefix = '%s[%d]' % (sName, oTestCase.idTestCase,);
663 self._add(' <tr class="%s">\n'
664 ' <td rowspan="%d">\n'
665 ' <input name="%s[%s]" type="hidden" value="%s">\n' # idTestCase
666 ' <input name="%s[%s]" type="hidden" value="%s">\n' # idTestGroup
667 ' <input name="%s[%s]" type="hidden" value="%s">\n' # tsExpire
668 ' <input name="%s[%s]" type="hidden" value="%s">\n' # tsEffective
669 ' <input name="%s[%s]" type="hidden" value="%s">\n' # uidAuthor
670 ' <input name="%s" type="checkbox"%s%s value="%d" class="tmform-checkbox" title="#%d - %s">\n' # (list)
671 ' </td>\n'
672 % ( 'tmodd' if iTestCase & 1 else 'tmeven',
673 len(oTestCase.aoTestCaseArgs),
674 sPrefix, TestGroupMemberData.ksParam_idTestCase, oTestCase.idTestCase,
675 sPrefix, TestGroupMemberData.ksParam_idTestGroup, -1 if oMember is None else oMember.idTestGroup,
676 sPrefix, TestGroupMemberData.ksParam_tsExpire, '' if oMember is None else oMember.tsExpire,
677 sPrefix, TestGroupMemberData.ksParam_tsEffective, '' if oMember is None else oMember.tsEffective,
678 sPrefix, TestGroupMemberData.ksParam_uidAuthor, '' if oMember is None else oMember.uidAuthor,
679 TestGroupDataEx.ksParam_aoMembers, '' if oMember is None else ' checked', sCheckBoxAttr,
680 oTestCase.idTestCase, oTestCase.idTestCase, escapeElem(oTestCase.sName),
681 ));
682 self._add(' <td rowspan="%d" align="left">%s</td>\n'
683 % ( len(oTestCase.aoTestCaseArgs), escapeElem(oTestCase.sName), ));
684
685 self._add(' <td rowspan="%d" title="Include all variations (checked) or choose a set?">\n'
686 ' <input name="%s[%s]" type="checkbox"%s%s value="-1">\n'
687 ' </td>\n'
688 % ( len(oTestCase.aoTestCaseArgs),
689 sPrefix, TestGroupMemberData.ksParam_aidTestCaseArgs,
690 ' checked' if oMember is None or oMember.aidTestCaseArgs is None else '', sCheckBoxAttr, ));
691
692 self._add(' <td rowspan="%d" align="center">\n'
693 ' <input name="%s[%s]" type="text" value="%s" style="max-width:3em;" %s>\n'
694 ' </td>\n'
695 % ( len(oTestCase.aoTestCaseArgs),
696 sPrefix, TestGroupMemberData.ksParam_iSchedPriority,
697 (oMember if oMember is not None else oDefMember).iSchedPriority,
698 ' readonly class="tmform-input-readonly"' if fReadOnly else '', ));
699
700 # Argument variations.
701 aidTestCaseArgs = [] if oMember is None or oMember.aidTestCaseArgs is None else oMember.aidTestCaseArgs;
702 for iVar in range(len(oTestCase.aoTestCaseArgs)):
703 oVar = oTestCase.aoTestCaseArgs[iVar];
704 if iVar > 0:
705 self._add(' <tr class="%s">\n' % ('tmodd' if iTestCase & 1 else 'tmeven',));
706 self._add(' <td align="center">\n'
707 ' <input name="%s[%s]" type="checkbox"%s%s value="%d">'
708 ' </td>\n'
709 % ( sPrefix, TestGroupMemberData.ksParam_aidTestCaseArgs,
710 ' checked' if oVar.idTestCaseArgs in aidTestCaseArgs else '', sCheckBoxAttr, oVar.idTestCaseArgs,
711 ));
712 self._add(' <td align="center">%s</td>\n'
713 ' <td align="center">%s</td>\n'
714 ' <td align="left">%s</td>\n'
715 % ( oVar.cGangMembers,
716 'Default' if oVar.cSecTimeout is None else oVar.cSecTimeout,
717 escapeElem(oVar.sArgs) ));
718
719 self._add(' </tr>\n');
720
721
722
723 if len(oTestCase.aoTestCaseArgs) == 0:
724 self._add(' <td></td> <td></td> <td></td> <td></td>\n'
725 ' </tr>\n');
726 return self._add(' </tbody>\n'
727 '</table>\n');
728
729 def addListOfSchedGroupMembers(self, sName, aoSchedGroupMembers, aoAllTestGroups, # pylint: disable=R0914
730 sLabel, fReadOnly = True):
731 """
732 For WuiAdminSchedGroup.
733 """
734 if self._fReadOnly:
735 fReadOnly = True;
736 assert len(aoSchedGroupMembers) <= len(aoAllTestGroups);
737 self._addLabel(sName, sLabel);
738 if len(aoAllTestGroups) == 0:
739 return self._add('<li>No test groups available.</li>\n')
740
741 self._add('<input name="%s" type="hidden" value="%s">\n'
742 % ( SchedGroupDataEx.ksParam_aidTestGroups,
743 ','.join([str(oTestGroup.idTestGroup) for oTestGroup in aoAllTestGroups]), ));
744
745 self._add('<table class="tmformtbl">\n'
746 ' <thead>\n'
747 ' <tr>\n'
748 ' <th></th>\n'
749 ' <th>Test Group</th>\n'
750 ' <th>Priority [0..31]</th>\n'
751 ' <th>Prerequisite Test Group</th>\n'
752 ' <th>Weekly schedule</th>\n'
753 ' </tr>\n'
754 ' </thead>\n'
755 ' <tbody>\n'
756 );
757
758 sCheckBoxAttr = ' readonly onclick="return false" onkeydown="return false"' if fReadOnly else '';
759 sComboBoxAttr = ' disabled' if fReadOnly else '';
760
761 oDefMember = SchedGroupMemberData();
762 aoSchedGroupMembers = list(aoSchedGroupMembers); # Copy it so we can pop.
763 for iTestGroup, _ in enumerate(aoAllTestGroups):
764 oTestGroup = aoAllTestGroups[iTestGroup];
765
766 # Is it a member?
767 oMember = None;
768 for i, _ in enumerate(aoSchedGroupMembers):
769 if aoSchedGroupMembers[i].oTestGroup.idTestGroup == oTestGroup.idTestGroup:
770 oMember = aoSchedGroupMembers.pop(i);
771 break;
772
773 # Start on the rows...
774 sPrefix = '%s[%d]' % (sName, oTestGroup.idTestGroup,);
775 self._add(' <tr class="%s">\n'
776 ' <td>\n'
777 ' <input name="%s[%s]" type="hidden" value="%s">\n' # idTestGroup
778 ' <input name="%s[%s]" type="hidden" value="%s">\n' # idSchedGroup
779 ' <input name="%s[%s]" type="hidden" value="%s">\n' # tsExpire
780 ' <input name="%s[%s]" type="hidden" value="%s">\n' # tsEffective
781 ' <input name="%s[%s]" type="hidden" value="%s">\n' # uidAuthor
782 ' <input name="%s" type="checkbox"%s%s value="%d" class="tmform-checkbox" title="#%d - %s">\n' # (list)
783 ' </td>\n'
784 % ( 'tmodd' if iTestGroup & 1 else 'tmeven',
785 sPrefix, SchedGroupMemberData.ksParam_idTestGroup, oTestGroup.idTestGroup,
786 sPrefix, SchedGroupMemberData.ksParam_idSchedGroup, -1 if oMember is None else oMember.idSchedGroup,
787 sPrefix, SchedGroupMemberData.ksParam_tsExpire, '' if oMember is None else oMember.tsExpire,
788 sPrefix, SchedGroupMemberData.ksParam_tsEffective, '' if oMember is None else oMember.tsEffective,
789 sPrefix, SchedGroupMemberData.ksParam_uidAuthor, '' if oMember is None else oMember.uidAuthor,
790 SchedGroupDataEx.ksParam_aoMembers, '' if oMember is None else ' checked', sCheckBoxAttr,
791 oTestGroup.idTestGroup, oTestGroup.idTestGroup, escapeElem(oTestGroup.sName),
792 ));
793 self._add(' <td align="left">%s</td>\n' % ( escapeElem(oTestGroup.sName), ));
794
795 self._add(' <td align="center">\n'
796 ' <input name="%s[%s]" type="text" value="%s" style="max-width:3em;" %s>\n'
797 ' </td>\n'
798 % ( sPrefix, SchedGroupMemberData.ksParam_iSchedPriority,
799 (oMember if oMember is not None else oDefMember).iSchedPriority,
800 ' readonly class="tmform-input-readonly"' if fReadOnly else '', ));
801
802 self._add(' <td align="center">\n'
803 ' <select name="%s[%s]" id="%s[%s]" class="tmform-combobox"%s>\n'
804 ' <option value="-1"%s>None</option>\n'
805 % ( sPrefix, SchedGroupMemberData.ksParam_idTestGroupPreReq,
806 sPrefix, SchedGroupMemberData.ksParam_idTestGroupPreReq,
807 sComboBoxAttr,
808 ' selected' if oMember is None or oMember.idTestGroupPreReq is None else '',
809 ));
810 for oTestGroup2 in aoAllTestGroups:
811 if oTestGroup2 != oTestGroup:
812 fSelected = oMember is not None and oTestGroup2.idTestGroup == oMember.idTestGroupPreReq;
813 self._add(' <option value="%s"%s>%s</option>\n'
814 % ( oTestGroup2.idTestGroup, ' selected' if fSelected else '', escapeElem(oTestGroup2.sName), ));
815 self._add(' </select>\n'
816 ' </td>\n');
817
818 self._add(' <td align="left">\n'
819 ' Todo<input name="%s[%s]" type="hidden" value="%s">\n'
820 ' </td>\n'
821 % ( sPrefix, SchedGroupMemberData.ksParam_bmHourlySchedule,
822 '' if oMember is None else oMember.bmHourlySchedule, ));
823
824 self._add(' </tr>\n');
825 return self._add(' </tbody>\n'
826 '</table>\n');
827
828 #
829 # Buttons.
830 #
831 def addSubmit(self, sLabel = 'Submit'):
832 """Adds the submit button to the form."""
833 if self._fReadOnly:
834 return True;
835 return self._add(' <li>\n'
836 ' <br>\n'
837 ' <div class="tmform-field"><div class="tmform-field-submit">\n'
838 ' <label>&nbsp;</label>\n'
839 ' <input type="submit" value="%s">\n'
840 ' </div></div>\n'
841 ' </li>\n'
842 % (escapeElem(sLabel),));
843
844 def addReset(self):
845 """Adds a reset button to the form."""
846 if self._fReadOnly:
847 return True;
848 return self._add(' <li>\n'
849 ' <div class="tmform-button"><div class="tmform-button-reset">\n'
850 ' <input type="reset" value="%s">\n'
851 ' </div></div>\n'
852 ' </li>\n'
853 );
854
Note: See TracBrowser for help on using the repository browser.

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