VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testdriver/vbox.py@ 53624

Last change on this file since 53624 was 53039, checked in by vboxsync, 10 years ago

TestManager: temporary reverted r95734: unfinished 'guru' state highlighting.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 138.5 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vbox.py 53039 2014-10-13 10:49:38Z vboxsync $
3# pylint: disable=C0302
4
5"""
6VirtualBox Specific base testdriver.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2014 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 53039 $"
31
32
33# Standard Python imports.
34import os
35import platform
36import sys
37import threading
38import time
39import traceback
40import datetime
41
42# Figure out where the validation kit lives and make sure it's in the path.
43try: __file__
44except: __file__ = sys.argv[0];
45g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)));
46if g_ksValidationKitDir not in sys.path:
47 sys.path.append(g_ksValidationKitDir);
48
49# Validation Kit imports.
50from common import utils;
51from testdriver import base;
52from testdriver import reporter;
53from testdriver import vboxcon;
54from testdriver import vboxtestvms;
55
56
57#
58# Exception and Error Unification Hacks.
59# Note! This is pretty gross stuff. Be warned!
60# TODO: Find better ways of doing these things, preferrably in vboxapi.
61#
62
63ComException = None; # pylint: disable=C0103
64__fnComExceptionGetAttr__ = None; # pylint: disable=C0103
65
66def __MyDefaultGetAttr(oSelf, sName):
67 """ __getattribute__/__getattr__ default fake."""
68 try:
69 oAttr = oSelf.__dict__[sName];
70 except:
71 oAttr = dir(oSelf)[sName];
72 return oAttr;
73
74def __MyComExceptionGetAttr(oSelf, sName):
75 """ ComException.__getattr__ wrapper - both XPCOM and COM. """
76 try:
77 oAttr = __fnComExceptionGetAttr__(oSelf, sName);
78 except AttributeError:
79 if platform.system() == 'Windows':
80 if sName == 'errno':
81 oAttr = __fnComExceptionGetAttr__(oSelf, 'hresult');
82 elif sName == 'msg':
83 oAttr = __fnComExceptionGetAttr__(oSelf, 'strerror');
84 else:
85 raise;
86 else:
87 if sName == 'hresult':
88 oAttr = __fnComExceptionGetAttr__(oSelf, 'errno');
89 elif sName == 'strerror':
90 oAttr = __fnComExceptionGetAttr__(oSelf, 'msg');
91 elif sName == 'excepinfo':
92 oAttr = None;
93 elif sName == 'argerror':
94 oAttr = None;
95 else:
96 raise;
97 #print '__MyComExceptionGetAttr(,%s) -> "%s"' % (sName, oAttr);
98 return oAttr;
99
100def __deployExceptionHacks__(oNativeComExceptionClass):
101 """
102 Deploys the exception and error hacks that helps unifying COM and XPCOM
103 exceptions and errors.
104 """
105 global ComException # pylint: disable=C0103
106 global __fnComExceptionGetAttr__ # pylint: disable=C0103
107
108 # Hook up our attribute getter for the exception class (ASSUMES new-style).
109 if __fnComExceptionGetAttr__ is None:
110 try:
111 __fnComExceptionGetAttr__ = getattr(oNativeComExceptionClass, '__getattr__');
112 except:
113 try:
114 __fnComExceptionGetAttr__ = getattr(oNativeComExceptionClass, '__getattribute__');
115 except:
116 __fnComExceptionGetAttr__ = __MyDefaultGetAttr;
117 setattr(oNativeComExceptionClass, '__getattr__', __MyComExceptionGetAttr)
118
119 # Make the modified classes accessible (are there better ways to do this?)
120 ComException = oNativeComExceptionClass
121 return None;
122
123
124
125#
126# Utility functions.
127#
128
129def isIpAddrValid(sIpAddr):
130 """
131 Checks if a IPv4 address looks valid. This will return false for
132 localhost and similar.
133 Returns True / False.
134 """
135 if sIpAddr is None: return False;
136 if len(sIpAddr.split('.')) != 4: return False;
137 if sIpAddr.endswith('.0'): return False;
138 if sIpAddr.endswith('.255'): return False;
139 if sIpAddr.startswith('127.'): return False;
140 if sIpAddr.startswith('169.254.'): return False;
141 if sIpAddr.startswith('192.0.2.'): return False;
142 if sIpAddr.startswith('224.0.0.'): return False;
143 return True;
144
145def stringifyErrorInfo(oErrInfo):
146 """
147 Stringifies the error information in a IVirtualBoxErrorInfo object.
148
149 Returns string with error info.
150 """
151 try:
152 rc = oErrInfo.resultCode;
153 sText = oErrInfo.text;
154 sIid = oErrInfo.interfaceID;
155 sComponent = oErrInfo.component;
156 except:
157 sRet = 'bad error object (%s)?' % (oErrInfo,);
158 traceback.print_exc();
159 else:
160 sRet = 'rc=%s text="%s" IID=%s component=%s' % (ComError.toString(rc), sText, sIid, sComponent);
161 return sRet;
162
163def reportError(oErr, sText):
164 """
165 Report a VirtualBox error on oErr. oErr can be IVirtualBoxErrorInfo
166 or IProgress. Anything else is ignored.
167
168 Returns the same a reporter.error().
169 """
170 try:
171 oErrObj = oErr.errorInfo; # IProgress.
172 except:
173 oErrObj = oErr;
174 reporter.error(sText);
175 return reporter.error(stringifyErrorInfo(oErrObj));
176
177
178#
179# Classes
180#
181
182class ComError(object):
183 """
184 Unified COM and XPCOM status code repository.
185 This works more like a module than a class since it's replacing a module.
186 """
187
188 # The VBOX_E_XXX bits:
189 __VBOX_E_BASE = -2135228416;
190 VBOX_E_OBJECT_NOT_FOUND = __VBOX_E_BASE + 1;
191 VBOX_E_INVALID_VM_STATE = __VBOX_E_BASE + 2;
192 VBOX_E_VM_ERROR = __VBOX_E_BASE + 3;
193 VBOX_E_FILE_ERROR = __VBOX_E_BASE + 4;
194 VBOX_E_IPRT_ERROR = __VBOX_E_BASE + 5;
195 VBOX_E_PDM_ERROR = __VBOX_E_BASE + 6;
196 VBOX_E_INVALID_OBJECT_STATE = __VBOX_E_BASE + 7;
197 VBOX_E_HOST_ERROR = __VBOX_E_BASE + 8;
198 VBOX_E_NOT_SUPPORTED = __VBOX_E_BASE + 9;
199 VBOX_E_XML_ERROR = __VBOX_E_BASE + 10;
200 VBOX_E_INVALID_SESSION_STATE = __VBOX_E_BASE + 11;
201 VBOX_E_OBJECT_IN_USE = __VBOX_E_BASE + 12;
202 VBOX_E_DONT_CALL_AGAIN = __VBOX_E_BASE + 13;
203
204 # Reverse lookup table.
205 dDecimalToConst = {}; # pylint: disable=C0103
206
207 def __init__(self):
208 raise base.GenError('No instances, please');
209
210 @staticmethod
211 def copyErrors(oNativeComErrorClass):
212 """
213 Copy all error codes from oNativeComErrorClass to this class and
214 install compatability mappings.
215 """
216
217 # First, add the VBOX_E_XXX constants to dDecimalToConst.
218 for sAttr in dir(ComError):
219 if sAttr.startswith('VBOX_E'):
220 oAttr = getattr(ComError, sAttr);
221 ComError.dDecimalToConst[oAttr] = sAttr;
222
223 # Copy all error codes from oNativeComErrorClass to this class.
224 for sAttr in dir(oNativeComErrorClass):
225 if sAttr[0].isupper():
226 oAttr = getattr(oNativeComErrorClass, sAttr);
227 setattr(ComError, sAttr, oAttr);
228 if type(oAttr) is int:
229 ComError.dDecimalToConst[oAttr] = sAttr;
230
231 # Install mappings to the other platform.
232 if platform.system() == 'Windows':
233 ComError.NS_OK = ComError.S_OK;
234 ComError.NS_ERROR_FAILURE = ComError.E_FAIL;
235 ComError.NS_ERROR_ABORT = ComError.E_ABORT;
236 ComError.NS_ERROR_NULL_POINTER = ComError.E_POINTER;
237 ComError.NS_ERROR_NO_INTERFACE = ComError.E_NOINTERFACE;
238 ComError.NS_ERROR_INVALID_ARG = ComError.E_INVALIDARG;
239 ComError.NS_ERROR_OUT_OF_MEMORY = ComError.E_OUTOFMEMORY;
240 ComError.NS_ERROR_NOT_IMPLEMENTED = ComError.E_NOTIMPL;
241 ComError.NS_ERROR_UNEXPECTED = ComError.E_UNEXPECTED;
242 else:
243 ComError.E_ACCESSDENIED = -2147024891; # see VBox/com/defs.h
244 ComError.S_OK = ComError.NS_OK;
245 ComError.E_FAIL = ComError.NS_ERROR_FAILURE;
246 ComError.E_ABORT = ComError.NS_ERROR_ABORT;
247 ComError.E_POINTER = ComError.NS_ERROR_NULL_POINTER;
248 ComError.E_NOINTERFACE = ComError.NS_ERROR_NO_INTERFACE;
249 ComError.E_INVALIDARG = ComError.NS_ERROR_INVALID_ARG;
250 ComError.E_OUTOFMEMORY = ComError.NS_ERROR_OUT_OF_MEMORY;
251 ComError.E_NOTIMPL = ComError.NS_ERROR_NOT_IMPLEMENTED;
252 ComError.E_UNEXPECTED = ComError.NS_ERROR_UNEXPECTED;
253 ComError.DISP_E_EXCEPTION = -2147352567; # For COM compatability only.
254 return True;
255
256 @staticmethod
257 def equal(oXcpt, hr):
258 """
259 Checks if the ComException e is not equal to the COM status code hr.
260 This takes DISP_E_EXCEPTION & excepinfo into account.
261
262 This method can be used with any Exception derivate, however it will
263 only return True for classes similar to the two ComException variants.
264 """
265 if platform.system() == 'Windows':
266 # The DISP_E_EXCEPTION + excptinfo fun needs checking up, only
267 # empirical info on it so far.
268 try:
269 hrXcpt = oXcpt.hresult;
270 except AttributeError:
271 return False;
272 if hrXcpt == ComError.DISP_E_EXCEPTION and oXcpt.excepinfo is not None:
273 hrXcpt = oXcpt.excepinfo[5];
274 else:
275 try:
276 hrXcpt = oXcpt.errno;
277 except AttributeError:
278 return False;
279 return hrXcpt == hr;
280
281 @staticmethod
282 def notEqual(oXcpt, hr):
283 """
284 Checks if the ComException e is not equal to the COM status code hr.
285 See equal() for more details.
286 """
287 return not ComError.equal(oXcpt, hr)
288
289 @staticmethod
290 def toString(hr):
291 """
292 Converts the specified COM status code to a string.
293 """
294 try:
295 sStr = ComError.dDecimalToConst[int(hr)];
296 except KeyError:
297 hrLong = long(hr);
298 sStr = '%#x (%d)' % (hrLong, hrLong);
299 return sStr;
300
301
302class Build(object): # pylint: disable=R0903
303 """
304 A VirtualBox build.
305
306 Note! After dropping the installation of VBox from this code and instead
307 realizing that with the vboxinstall.py wrapper driver, this class is
308 of much less importance and contains unnecessary bits and pieces.
309 """
310
311 def __init__(self, oDriver, strInstallPath):
312 """
313 Construct a build object from a build file name and/or install path.
314 """
315 # Initialize all members first.
316 self.oDriver = oDriver;
317 self.sInstallPath = strInstallPath;
318 self.sSdkPath = None;
319 self.sSrcRoot = None;
320 self.sKind = None;
321 self.sDesignation = None;
322 self.sType = None;
323 self.sOs = None;
324 self.sArch = None;
325 self.sGuestAdditionsIso = None;
326
327 # Figure out the values as best we can.
328 if strInstallPath is None:
329 #
330 # Both parameters are None, which means we're falling back on a
331 # build in the development tree.
332 #
333 self.sKind = "development";
334
335 if self.sType is None:
336 self.sType = os.environ.get("KBUILD_TYPE", os.environ.get("BUILD_TYPE", "release"));
337 if self.sOs is None:
338 self.sOs = os.environ.get("KBUILD_TARGET", os.environ.get("BUILD_TARGET", oDriver.sHost));
339 if self.sArch is None:
340 self.sArch = os.environ.get("KBUILD_TARGET_ARCH", os.environ.get("BUILD_TARGET_ARCH", oDriver.sHostArch));
341
342 sOut = os.path.join('out', self.sOs + '.' + self.sArch, self.sType);
343 sSearch = os.environ.get('VBOX_TD_DEV_TREE', os.path.dirname(__file__)); # Env.var. for older trees or testboxscript.
344 sCandidat = None;
345 for i in range(0, 10): # pylint: disable=W0612
346 sBldDir = os.path.join(sSearch, sOut);
347 if os.path.isdir(sBldDir):
348 sCandidat = os.path.join(sBldDir, 'bin', 'VBoxSVC' + base.exeSuff());
349 if os.path.isfile(sCandidat):
350 self.sSdkPath = os.path.join(sBldDir, 'bin/sdk');
351 break;
352 sCandidat = os.path.join(sBldDir, 'dist/VirtualBox.app/Contents/MacOS/VBoxSVC');
353 if os.path.isfile(sCandidat):
354 self.sSdkPath = os.path.join(sBldDir, 'dist/sdk');
355 break;
356 sSearch = os.path.abspath(os.path.join(sSearch, '..'));
357 if sCandidat is None or not os.path.isfile(sCandidat):
358 raise base.GenError();
359 self.sInstallPath = os.path.abspath(os.path.dirname(sCandidat));
360 self.sSrcRoot = os.path.abspath(sSearch);
361
362 self.sDesignation = os.environ.get('TEST_BUILD_DESIGNATION', None);
363 if self.sDesignation is None:
364 try:
365 oFile = utils.openNoInherit(os.path.join(self.sSrcRoot, sOut, 'revision.kmk'), 'r');
366 except:
367 pass;
368 else:
369 s = oFile.readline();
370 oFile.close();
371 import re;
372 oMatch = re.search("VBOX_SVN_REV=(\\d+)", s);
373 if oMatch is not None:
374 self.sDesignation = oMatch.group(1);
375
376 if self.sDesignation is None:
377 self.sDesignation = 'XXXXX'
378 else:
379 #
380 # We've been pointed to an existing installation, this could be
381 # in the out dir of a svn checkout, untarred VBoxAll or a real
382 # installation directory.
383 #
384 self.sKind = "preinstalled";
385 self.sType = "release";
386 self.sOs = oDriver.sHost;
387 self.sArch = oDriver.sHostArch;
388 self.sInstallPath = os.path.abspath(strInstallPath);
389 self.sSdkPath = os.path.join(self.sInstallPath, 'sdk');
390 self.sSrcRoot = None;
391 self.sDesignation = os.environ.get('TEST_BUILD_DESIGNATION', 'XXXXX');
392 ## @todo Much more work is required here.
393
394 # Do some checks.
395 sVMMR0 = os.path.join(self.sInstallPath, 'VMMR0.r0');
396 if not os.path.isfile(sVMMR0) and utils.getHostOs() == 'solaris': # solaris is special.
397 sVMMR0 = os.path.join(self.sInstallPath, 'amd64' if utils.getHostArch() == 'amd64' else 'i386', 'VMMR0.r0');
398 if not os.path.isfile(sVMMR0):
399 raise base.GenError('%s is missing' % (sVMMR0,));
400
401 # Guest additions location is different on windows for some _stupid_ reason.
402 if self.sOs == 'win' and self.sKind != 'development':
403 self.sGuestAdditionsIso = '%s/VBoxGuestAdditions.iso' % (self.sInstallPath,);
404 elif self.sOs == 'darwin':
405 self.sGuestAdditionsIso = '%s/VBoxGuestAdditions.iso' % (self.sInstallPath,);
406 else:
407 self.sGuestAdditionsIso = '%s/additions/VBoxGuestAdditions.iso' % (self.sInstallPath,);
408
409 # __init__ end;
410
411 def dump(self):
412 """ Status dumper for debugging. """
413 print >> sys.stderr, "testdriver.vbox.Build: sInstallPath= '%s'" % self.sInstallPath;
414 print >> sys.stderr, "testdriver.vbox.Build: sSdkPath = '%s'" % self.sSdkPath;
415 print >> sys.stderr, "testdriver.vbox.Build: sSrcRoot = '%s'" % self.sSrcRoot;
416 print >> sys.stderr, "testdriver.vbox.Build: sKind = '%s'" % self.sKind;
417 print >> sys.stderr, "testdriver.vbox.Build: sDesignation= '%s'" % self.sDesignation;
418 print >> sys.stderr, "testdriver.vbox.Build: sType = '%s'" % self.sType;
419 print >> sys.stderr, "testdriver.vbox.Build: sOs = '%s'" % self.sOs;
420 print >> sys.stderr, "testdriver.vbox.Build: sArch = '%s'" % self.sArch;
421
422 def isDevBuild(self):
423 """ Returns True if it's development build (kind), otherwise False. """
424 return self.sKind == 'development';
425
426
427class EventHandlerBase(object):
428 """
429 Base class for both Console and VirtualBox event handlers.
430 """
431
432 def __init__(self, dArgs, fpApiVer, sName = None):
433 self.oVBoxMgr = dArgs['oVBoxMgr'];
434 self.oEventSrc = dArgs['oEventSrc']; # Console/VirtualBox for < 3.3
435 self.oListener = dArgs['oListener'];
436 self.fPassive = self.oListener != None;
437 self.sName = sName
438 self.fShutdown = False;
439 self.oThread = None;
440 self.fpApiVer = fpApiVer;
441
442 def threadForPassiveMode(self):
443 """
444 The thread procedure for the event processing thread.
445 """
446 assert self.fPassive is not None;
447 while not self.fShutdown:
448 try:
449 oEvt = self.oEventSrc.getEvent(self.oListener, 500);
450 except:
451 if not self.oVBoxMgr.xcptIsDeadInterface(): reporter.logXcpt();
452 else: reporter.log('threadForPassiveMode/%s: interface croaked (ignored)' % (self.sName,));
453 break;
454 if oEvt:
455 self.handleEvent(oEvt);
456 try:
457 self.oEventSrc.eventProcessed(self.oListener, oEvt);
458 except:
459 reporter.logXcpt();
460 break;
461 self.unregister(fWaitForThread = False);
462 return None;
463
464 def startThreadForPassiveMode(self):
465 """
466 Called when working in passive mode.
467 """
468 self.oThread = threading.Thread(target = self.threadForPassiveMode, \
469 args=(), name=('PAS-%s' % (self.sName,)));
470 self.oThread.setDaemon(True)
471 self.oThread.start();
472 return None;
473
474 def unregister(self, fWaitForThread = True):
475 """
476 Unregister the event handler.
477 """
478 self.fShutdown = True;
479
480 fRc = False;
481 if self.oEventSrc is not None:
482 if self.fpApiVer < 3.3:
483 try:
484 self.oEventSrc.unregisterCallback(self.oListener);
485 fRc = True;
486 except:
487 reporter.errorXcpt('unregisterCallback failed on %s' % (self.oListener,));
488 else:
489 try:
490 self.oEventSrc.unregisterListener(self.oListener);
491 fRc = True;
492 except:
493 if self.oVBoxMgr.xcptIsDeadInterface():
494 reporter.log('unregisterListener failed on %s because of dead interface (%s)'
495 % (self.oListener, self.oVBoxMgr.xcptToString(),));
496 else:
497 reporter.errorXcpt('unregisterListener failed on %s' % (self.oListener,));
498
499 if self.oThread is not None \
500 and self.oThread != threading.current_thread():
501 self.oThread.join();
502 self.oThread = None;
503
504 _ = fWaitForThread;
505 return fRc;
506
507 def handleEvent(self, oEvt):
508 """
509 Compatibility wrapper that child classes implement.
510 """
511 _ = oEvt;
512 return None;
513
514 @staticmethod
515 def registerDerivedEventHandler(oVBoxMgr, fpApiVer, oSubClass, dArgsCopy,
516 oSrcParent, sSrcParentNm, sICallbackNm,
517 fMustSucceed = True, sLogSuffix = ''):
518 """
519 Registers the callback / event listener.
520 """
521 dArgsCopy['oVBoxMgr'] = oVBoxMgr;
522 dArgsCopy['oListener'] = None;
523 if fpApiVer < 3.3:
524 dArgsCopy['oEventSrc'] = oSrcParent;
525 try:
526 oRet = oVBoxMgr.createCallback(sICallbackNm, oSubClass, dArgsCopy);
527 except:
528 reporter.errorXcpt('%s::registerCallback(%s) failed%s' % (sSrcParentNm, oRet, sLogSuffix));
529 else:
530 try:
531 oSrcParent.registerCallback(oRet);
532 return oRet;
533 except Exception, oXcpt:
534 if fMustSucceed or ComError.notEqual(oXcpt, ComError.E_UNEXPECTED):
535 reporter.errorXcpt('%s::registerCallback(%s)%s' % (sSrcParentNm, oRet, sLogSuffix));
536 else:
537 fPassive = sys.platform == 'win32'; # or webservices.
538 try:
539 oEventSrc = oSrcParent.eventSource;
540 dArgsCopy['oEventSrc'] = oEventSrc;
541 if not fPassive:
542 oListener = oRet = oVBoxMgr.createListener(oSubClass, dArgsCopy);
543 else:
544 oListener = oEventSrc.createListener();
545 dArgsCopy['oListener'] = oListener;
546 oRet = oSubClass(dArgsCopy);
547 except:
548 reporter.errorXcpt('%s::eventSource.createListener(%s) failed%s' % (sSrcParentNm, oListener, sLogSuffix));
549 else:
550 try:
551 oEventSrc.registerListener(oListener, [vboxcon.VBoxEventType_Any], not fPassive);
552 except Exception, oXcpt:
553 if fMustSucceed or ComError.notEqual(oXcpt, ComError.E_UNEXPECTED):
554 reporter.errorXcpt('%s::eventSource.registerListener(%s) failed%s' \
555 % (sSrcParentNm, oListener, sLogSuffix));
556 else:
557 if not fPassive:
558 if sys.platform == 'win32':
559 from win32com.server.util import unwrap # pylint: disable=F0401
560 oRet = unwrap(oRet);
561 oRet.oListener = oListener;
562 else:
563 oRet.startThreadForPassiveMode();
564 return oRet;
565 return None;
566
567
568
569
570class ConsoleEventHandlerBase(EventHandlerBase):
571 """
572 Base class for handling IConsole events.
573
574 The class has IConsoleCallback (<=3.2) compatible callback methods which
575 the user can override as needed.
576
577 Note! This class must not inherit from object or we'll get type errors in VBoxPython.
578 """
579 def __init__(self, dArgs, sName = None):
580 self.oSession = dArgs['oSession'];
581 self.oConsole = dArgs['oConsole'];
582 if sName is None:
583 sName = self.oSession.sName;
584 EventHandlerBase.__init__(self, dArgs, self.oSession.fpApiVer, sName);
585
586
587 # pylint: disable=C0111,R0913,W0613
588 def onMousePointerShapeChange(self, fVisible, fAlpha, xHot, yHot, cx, cy, abShape):
589 reporter.log2('onMousePointerShapeChange/%s' % (self.sName));
590 def onMouseCapabilityChange(self, fSupportsAbsolute, *aArgs): # Extra argument was added in 3.2.
591 reporter.log2('onMouseCapabilityChange/%s' % (self.sName));
592 def onKeyboardLedsChange(self, fNumLock, fCapsLock, fScrollLock):
593 reporter.log2('onKeyboardLedsChange/%s' % (self.sName));
594 def onStateChange(self, eState):
595 reporter.log2('onStateChange/%s' % (self.sName));
596 def onAdditionsStateChange(self):
597 reporter.log2('onAdditionsStateChange/%s' % (self.sName));
598 def onNetworkAdapterChange(self, oNic):
599 reporter.log2('onNetworkAdapterChange/%s' % (self.sName));
600 def onSerialPortChange(self, oPort):
601 reporter.log2('onSerialPortChange/%s' % (self.sName));
602 def onParallelPortChange(self, oPort):
603 reporter.log2('onParallelPortChange/%s' % (self.sName));
604 def onStorageControllerChange(self):
605 reporter.log2('onStorageControllerChange/%s' % (self.sName));
606 def onMediumChange(self, attachment):
607 reporter.log2('onMediumChange/%s' % (self.sName));
608 def onCPUChange(self, iCpu, fAdd):
609 reporter.log2('onCPUChange/%s' % (self.sName));
610 def onVRDPServerChange(self):
611 reporter.log2('onVRDPServerChange/%s' % (self.sName));
612 def onRemoteDisplayInfoChange(self):
613 reporter.log2('onRemoteDisplayInfoChange/%s' % (self.sName));
614 def onUSBControllerChange(self):
615 reporter.log2('onUSBControllerChange/%s' % (self.sName));
616 def onUSBDeviceStateChange(self, oDevice, fAttached, oError):
617 reporter.log2('onUSBDeviceStateChange/%s' % (self.sName));
618 def onSharedFolderChange(self, fGlobal):
619 reporter.log2('onSharedFolderChange/%s' % (self.sName));
620 def onRuntimeError(self, fFatal, sErrId, sMessage):
621 reporter.log2('onRuntimeError/%s' % (self.sName));
622 def onCanShowWindow(self):
623 reporter.log2('onCanShowWindow/%s' % (self.sName));
624 return True
625 def onShowWindow(self):
626 reporter.log2('onShowWindow/%s' % (self.sName));
627 return None;
628
629 # pylint: enable=C0111,R0913,W0613
630
631 def handleEvent(self, oEvt):
632 """
633 Compatibility wrapper.
634 """
635 try:
636 oEvtBase = self.oVBoxMgr.queryInterface(oEvt, 'IEvent');
637 eType = oEvtBase.type;
638 except:
639 reporter.logXcpt();
640 return None;
641 if eType == vboxcon.VBoxEventType_OnRuntimeError:
642 try:
643 oEvtIt = self.oVBoxMgr.queryInterface(oEvtBase, 'IRuntimeErrorEvent');
644 return self.onRuntimeError(oEvtIt.fatal, oEvtIt.id, oEvtIt.message)
645 except:
646 reporter.logXcpt();
647 ## @todo implement the other events.
648 if eType != vboxcon.VBoxEventType_OnMousePointerShapeChanged:
649 reporter.log2('%s/%s' % (str(eType), self.sName));
650 return None;
651
652
653class VirtualBoxEventHandlerBase(EventHandlerBase):
654 """
655 Base class for handling IVirtualBox events.
656
657 The class has IConsoleCallback (<=3.2) compatible callback methods which
658 the user can override as needed.
659
660 Note! This class must not inherit from object or we'll get type errors in VBoxPython.
661 """
662 def __init__(self, dArgs, sName = "emanon"):
663 self.oVBoxMgr = dArgs['oVBoxMgr'];
664 self.oVBox = dArgs['oVBox'];
665 EventHandlerBase.__init__(self, dArgs, self.oVBox.fpApiVer, sName);
666
667 # pylint: disable=C0111,W0613
668 def onMachineStateChange(self, sMachineId, eState):
669 pass;
670 def onMachineDataChange(self, sMachineId):
671 pass;
672 def onExtraDataCanChange(self, sMachineId, sKey, sValue):
673 # The COM bridge does tuples differently. Not very funny if you ask me... ;-)
674 if self.oVBoxMgr.type == 'MSCOM':
675 return '', 0, True;
676 return True, ''
677 def onExtraDataChange(self, sMachineId, sKey, sValue):
678 pass;
679 def onMediumRegistered(self, sMediumId, eMediumType, fRegistered):
680 pass;
681 def onMachineRegistered(self, sMachineId, fRegistered):
682 pass;
683 def onSessionStateChange(self, sMachineId, eState):
684 pass;
685 def onSnapshotTaken(self, sMachineId, sSnapshotId):
686 pass;
687 def onSnapshotDiscarded(self, sMachineId, sSnapshotId):
688 pass;
689 def onSnapshotChange(self, sMachineId, sSnapshotId):
690 pass;
691 def onGuestPropertyChange(self, sMachineId, sName, sValue, sFlags):
692 pass;
693 # pylint: enable=C0111,W0613
694
695 def handleEvent(self, oEvt):
696 """
697 Compatibility wrapper.
698 """
699 try:
700 oEvtBase = self.oVBoxMgr.queryInterface(oEvt, 'IEvent');
701 eType = oEvtBase.type;
702 except:
703 reporter.logXcpt();
704 return None;
705 if eType == vboxcon.VBoxEventType_OnMachineStateChanged:
706 try:
707 oEvtIt = self.oVBoxMgr.queryInterface(oEvtBase, 'IMachineStateChangedEvent');
708 return self.onMachineStateChange(oEvtIt.machineId, oEvtIt.state)
709 except:
710 reporter.logXcpt();
711 elif eType == vboxcon.VBoxEventType_OnGuestPropertyChanged:
712 try:
713 oEvtIt = self.oVBoxMgr.queryInterface(oEvtBase, 'IGuestPropertyChangedEvent');
714 return self.onGuestPropertyChange(oEvtIt.machineId, oEvtIt.name, oEvtIt.value, oEvtIt.flags);
715 except:
716 reporter.logXcpt();
717 ## @todo implement the other events.
718 reporter.log2('%s/%s' % (str(eType), self.sName));
719 return None;
720
721
722class SessionConsoleEventHandler(ConsoleEventHandlerBase):
723 """
724 For catching machine state changes and waking up the task machinery at that point.
725 """
726 def __init__(self, dArgs):
727 ConsoleEventHandlerBase.__init__(self, dArgs);
728
729 def onMachineStateChange(self, sMachineId, eState): # pylint: disable=W0613
730 """ Just interrupt the wait loop here so it can check again. """
731 self.oVBoxMgr.interruptWaitEvents();
732
733
734
735class TestDriver(base.TestDriver): # pylint: disable=R0902
736 """
737 This is the VirtualBox test driver.
738 """
739
740 def __init__(self):
741 base.TestDriver.__init__(self);
742 self.fImportedVBoxApi = False;
743 self.fpApiVer = 3.2;
744 self.oBuild = None;
745 self.oVBoxMgr = None;
746 self.oVBox = None;
747 self.aoRemoteSessions = [];
748 self.aoVMs = []; ## @todo not sure if this list will be of any use.
749 self.oTestVmManager = vboxtestvms.TestVmManager(self.sResourcePath);
750 self.oTestVmSet = vboxtestvms.TestVmSet();
751 self.sSessionTypeDef = 'headless';
752 self.sSessionType = self.sSessionTypeDef;
753 self.fEnableVrdp = True;
754 self.uVrdpBasePortDef = 6000;
755 self.uVrdpBasePort = self.uVrdpBasePortDef;
756 self.sDefBridgedNic = None;
757 self.fUseDefaultSvc = False;
758 self.sLogSelfGroups = '';
759 self.sLogSelfFlags = 'time';
760 self.sLogSelfDest = '';
761 self.sLogSessionGroups = '';
762 self.sLogSessionFlags = 'time';
763 self.sLogSessionDest = '';
764 self.sLogSvcGroups = '';
765 self.sLogSvcFlags = 'time';
766 self.sLogSvcDest = '';
767 self.sSelfLogFile = None;
768 self.sVBoxSvcLogFile = None;
769 self.oVBoxSvcProcess = None;
770 self.sVBoxSvcPidFile = None;
771 self.fVBoxSvcInDebugger = False;
772 self.sVBoxValidationKit = None;
773 self.sVBoxValidationKitIso = None;
774 self.sVBoxBootSectors = None;
775 self.fAlwaysUploadLogs = False;
776 self.fAlwaysUploadScreenshots = False;
777
778 # Quietly detect build and validation kit.
779 self._detectBuild(False);
780 self._detectValidationKit(False);
781
782 # Make sure all debug logs goes to the scratch area unless
783 # specified otherwise (more of this later on).
784 if 'VBOX_LOG_DEST' not in os.environ:
785 os.environ['VBOX_LOG_DEST'] = 'dir=%s' % (self.sScratchPath);
786
787 def dump(self):
788 """
789 Dump object state, for debugging.
790 """
791 base.TestDriver.dump(self);
792 print >> sys.stderr, "testdriver.vbox: fImportedVBoxApi = '%s'" % self.fImportedVBoxApi;
793 print >> sys.stderr, "testdriver.vbox: fpApiVer = '%s'" % self.fpApiVer;
794 print >> sys.stderr, "testdriver.vbox: oBuild = '%s'" % self.oBuild;
795 print >> sys.stderr, "testdriver.vbox: oVBoxMgr = '%s'" % self.oVBoxMgr;
796 print >> sys.stderr, "testdriver.vbox: oVBox = '%s'" % self.oVBox;
797 print >> sys.stderr, "testdriver.vbox: aoRemoteSessions = '%s'" % self.aoRemoteSessions;
798 print >> sys.stderr, "testdriver.vbox: aoVMs = '%s'" % self.aoVMs;
799 print >> sys.stderr, "testdriver.vbox: sVBoxValidationKit = '%s'" % self.sVBoxValidationKit;
800 print >> sys.stderr, "testdriver.vbox: sVBoxValidationKitIso = '%s'" % self.sVBoxValidationKitIso;
801 print >> sys.stderr, "testdriver.vbox: sVBoxBootSectors = '%s'" % self.sVBoxBootSectors;
802 if self.oBuild is not None:
803 self.oBuild.dump();
804
805 def _detectBuild(self, fQuiet = False):
806 """
807 This is used internally to try figure a locally installed build when
808 running tests manually.
809 """
810 if self.oBuild is not None:
811 return True;
812
813 # Try dev build first since that's where I'll be using it first..
814 if True:
815 try:
816 self.oBuild = Build(self, None);
817 return True;
818 except base.GenError:
819 pass;
820
821 # Try default installation locations.
822 if self.sHost == 'win':
823 sProgFiles = os.environ.get('ProgramFiles', 'C:\\Program Files');
824 asLocs = [
825 os.path.join(sProgFiles, 'Oracle', 'VirtualBox'),
826 os.path.join(sProgFiles, 'OracleVM', 'VirtualBox'),
827 os.path.join(sProgFiles, 'Sun', 'VirtualBox'),
828 ];
829 elif self.sHost == 'solaris':
830 asLocs = [ '/opt/VirtualBox-3.2', '/opt/VirtualBox-3.1', '/opt/VirtualBox-3.0', '/opt/VirtualBox' ];
831 elif self.sHost == 'darwin':
832 asLocs = [ '/Applications/VirtualBox.app/Contents/MacOS' ];
833 elif self.sHost == 'linux':
834 asLocs = [ '/opt/VirtualBox-3.2', '/opt/VirtualBox-3.1', '/opt/VirtualBox-3.0', '/opt/VirtualBox' ];
835 else:
836 asLocs = [ '/opt/VirtualBox' ];
837 if 'VBOX_INSTALL_PATH' in os.environ:
838 asLocs.insert(0, os.environ['VBOX_INSTALL_PATH']);
839
840 for sLoc in asLocs:
841 try:
842 self.oBuild = Build(self, sLoc);
843 return True;
844 except base.GenError:
845 pass;
846
847 if not fQuiet:
848 reporter.error('failed to find VirtualBox installation');
849 return False;
850
851 def _detectValidationKit(self, fQuiet = False):
852 """
853 This is used internally by the constructor to try locate an unzipped
854 VBox Validation Kit somewhere in the immediate proximity.
855 """
856 if self.sVBoxValidationKit is not None:
857 return True;
858
859 #
860 # Normally it's found where we're running from, which is the same as
861 # the script directly on the testboxes.
862 #
863 asCandidates = [self.sScriptPath, ];
864 if g_ksValidationKitDir not in asCandidates:
865 asCandidates.append(g_ksValidationKitDir);
866 if os.getcwd() not in asCandidates:
867 asCandidates.append(os.getcwd());
868 if self.oBuild is not None and self.oBuild.sInstallPath not in asCandidates:
869 asCandidates.append(self.oBuild.sInstallPath);
870
871 #
872 # When working out of the tree, we'll search the current directory
873 # as well as parent dirs.
874 #
875 for sDir in list(asCandidates):
876 for i in range(10):
877 sDir = os.path.dirname(sDir);
878 if sDir not in asCandidates:
879 asCandidates.append(sDir);
880
881 #
882 # Do the searching.
883 #
884 sCandidate = None;
885 for i in range(len(asCandidates)):
886 sCandidate = asCandidates[i];
887 if os.path.isfile(os.path.join(sCandidate, 'VBoxValidationKit.iso')):
888 break;
889 sCandidate = os.path.join(sCandidate, 'validationkit');
890 if os.path.isfile(os.path.join(sCandidate, 'VBoxValidationKit.iso')):
891 break;
892 sCandidate = None;
893
894 fRc = sCandidate is not None;
895 if fRc is False:
896 if not fQuiet:
897 reporter.error('failed to find VBox Validation Kit installation (candidates: %s)' % (asCandidates,));
898 sCandidate = os.path.join(self.sScriptPath, 'validationkit'); # Don't leave the values as None.
899
900 #
901 # Set the member values.
902 #
903 self.sVBoxValidationKit = sCandidate;
904 self.sVBoxValidationKitIso = os.path.join(sCandidate, 'VBoxValidationKit.iso');
905 self.sVBoxBootSectors = os.path.join(sCandidate, 'bootsectors');
906 return fRc;
907
908 def importVBoxApi(self):
909 """
910 Import the 'vboxapi' module from the VirtualBox build we're using and
911 instantiate the two basic objects.
912
913 This will try detect an development or installed build if no build has
914 been associated with the driver yet.
915 """
916 if self.fImportedVBoxApi:
917 return True;
918
919 ## @todo split up this messy function.
920
921 # Make sure we've got our own VirtualBox config and VBoxSVC (on XPCOM at least).
922 if not self.fUseDefaultSvc:
923 os.environ['VBOX_USER_HOME'] = os.path.join(self.sScratchPath, 'VBoxUserHome');
924 sUser = os.environ.get('USERNAME', os.environ.get('USER', os.environ.get('LOGNAME', 'unknown')));
925 os.environ['VBOX_IPC_SOCKETID'] = sUser + '-VBoxTest';
926
927 # Do the detecting.
928 self._detectBuild();
929 if self.oBuild is None:
930 return False;
931
932 # Avoid crashing when loading the 32-bit module (or whatever it is that goes bang).
933 if self.oBuild.sArch == 'x86' \
934 and self.sHost == 'darwin' \
935 and platform.architecture()[0] == '64bit' \
936 and self.oBuild.sKind == 'development' \
937 and os.getenv('VERSIONER_PYTHON_PREFER_32_BIT') != 'yes':
938 print "WARNING: 64-bit python on darwin, 32-bit VBox development build => crash"
939 print "WARNING: bash-3.2$ /usr/bin/python2.5 ./testdriver"
940 print "WARNING: or"
941 print "WARNING: bash-3.2$ VERSIONER_PYTHON_PREFER_32_BIT=yes ./testdriver"
942 return False;
943
944 # Start VBoxSVC and load the vboxapi bits.
945 if self._startVBoxSVC() is True:
946 assert(self.oVBoxSvcProcess is not None);
947
948 sSavedSysPath = sys.path;
949 self._setupVBoxApi();
950 sys.path = sSavedSysPath;
951
952 # Adjust the default machine folder.
953 if self.fImportedVBoxApi and not self.fUseDefaultSvc and self.fpApiVer >= 4.0:
954 sNewFolder = os.path.join(self.sScratchPath, 'VBoxUserHome', 'Machines');
955 try:
956 self.oVBox.systemProperties.defaultMachineFolder = sNewFolder;
957 except:
958 self.fImportedVBoxApi = False;
959 self.oVBoxMgr = None;
960 self.oVBox = None;
961 reporter.logXcpt("defaultMachineFolder exception (sNewFolder=%s)" % (sNewFolder,));
962
963 # Kill VBoxSVC on failure.
964 if self.oVBoxMgr is None:
965 self._stopVBoxSVC();
966 else:
967 assert(self.oVBoxSvcProcess is None);
968 return self.fImportedVBoxApi;
969
970 def _startVBoxSVC(self): # pylint: disable=R0915
971 """ Starts VBoxSVC. """
972 assert(self.oVBoxSvcProcess is None);
973
974 # Setup vbox logging for VBoxSVC now and start it manually. This way
975 # we can control both logging and shutdown.
976 self.sVBoxSvcLogFile = '%s/VBoxSVC-debug.log' % (self.sScratchPath,);
977 try: os.remove(self.sVBoxSvcLogFile);
978 except: pass;
979 os.environ['VBOX_LOG'] = self.sLogSvcGroups;
980 os.environ['VBOX_LOG_FLAGS'] = '%s append' % (self.sLogSvcFlags,); # Append becuse of VBoxXPCOMIPCD.
981 if self.sLogSvcDest:
982 os.environ['VBOX_LOG_DEST'] = self.sLogSvcDest;
983 else:
984 os.environ['VBOX_LOG_DEST'] = 'file=%s' % (self.sVBoxSvcLogFile,);
985 os.environ['VBOXSVC_RELEASE_LOG_FLAGS'] = 'time append';
986
987 # Always leave a pid file behind so we can kill it during cleanup-before.
988 self.sVBoxSvcPidFile = '%s/VBoxSVC.pid' % (self.sScratchPath,);
989 fWritePidFile = True;
990
991 cMsFudge = 1;
992 sVBoxSVC = '%s/VBoxSVC' % (self.oBuild.sInstallPath,); ## @todo .exe and stuff.
993 if self.fVBoxSvcInDebugger:
994 if self.sHost in ('darwin', 'freebsd', 'linux', 'solaris', ):
995 # Start VBoxSVC in gdb in a new terminal.
996 #sTerm = '/usr/bin/gnome-terminal'; - doesn't work, some fork+exec stuff confusing us.
997 sTerm = '/usr/bin/xterm';
998 if not os.path.isfile(sTerm): sTerm = '/usr/X11/bin/xterm';
999 if not os.path.isfile(sTerm): sTerm = '/usr/X11R6/bin/xterm';
1000 if not os.path.isfile(sTerm): sTerm = '/usr/bin/xterm';
1001 if not os.path.isfile(sTerm): sTerm = 'xterm';
1002 sGdb = '/usr/bin/gdb';
1003 if not os.path.isfile(sGdb): sGdb = '/usr/local/bin/gdb';
1004 if not os.path.isfile(sGdb): sGdb = '/usr/sfw/bin/gdb';
1005 if not os.path.isfile(sGdb): sGdb = 'gdb';
1006 sGdbCmdLine = '%s --args %s --pidfile %s' % (sGdb, sVBoxSVC, self.sVBoxSvcPidFile);
1007 reporter.log('term="%s" gdb="%s"' % (sTerm, sGdbCmdLine));
1008 os.environ['SHELL'] = self.sOrgShell; # Non-working shell may cause gdb and/or the term problems.
1009 self.oVBoxSvcProcess = base.Process.spawnp(sTerm, sTerm, '-e', sGdbCmdLine);
1010 os.environ['SHELL'] = self.sOurShell;
1011 if self.oVBoxSvcProcess is not None:
1012 reporter.log('Press enter or return after starting VBoxSVC in the debugger...');
1013 sys.stdin.read(1);
1014 fWritePidFile = False;
1015
1016 elif self.sHost == 'win':
1017 sWinDbg = 'c:\\Program Files\\Debugging Tools for Windows\\windbg.exe';
1018 if not os.path.isfile(sWinDbg): sWinDbg = 'c:\\Program Files\\Debugging Tools for Windows (x64)\\windbg.exe';
1019 if not os.path.isfile(sWinDbg): sWinDbg = 'c:\\Programme\\Debugging Tools for Windows\\windbg.exe'; # Localization rulez! pylint: disable=C0301
1020 if not os.path.isfile(sWinDbg): sWinDbg = 'c:\\Programme\\Debugging Tools for Windows (x64)\\windbg.exe';
1021 if not os.path.isfile(sWinDbg): sWinDbg = 'windbg'; # WinDbg must be in the path; better than nothing.
1022 # Assume that everything WinDbg needs is defined using the environment variables.
1023 # See WinDbg help for more information.
1024 reporter.log('windbg="%s"' % (sWinDbg));
1025 self.oVBoxSvcProcess = base.Process.spawn(sWinDbg, sWinDbg, sVBoxSVC + base.exeSuff());
1026 if self.oVBoxSvcProcess is not None:
1027 reporter.log('Press enter or return after starting VBoxSVC in the debugger...');
1028 sys.stdin.read(1);
1029 fWritePidFile = False;
1030 ## @todo add a pipe interface similar to xpcom if feasible, i.e. if
1031 # we can get actual handle values for pipes in python.
1032
1033 else:
1034 reporter.error('Port me!');
1035 else: # Run without a debugger attached.
1036 if self.sHost in ('darwin', 'freebsd', 'linux', 'solaris', ):
1037 #
1038 # XPCOM - We can use a pipe to let VBoxSVC notify us when it's ready.
1039 #
1040 iPipeR, iPipeW = os.pipe();
1041 os.environ['NSPR_INHERIT_FDS'] = 'vboxsvc:startup-pipe:5:0x%x' % (iPipeW,);
1042 reporter.log2("NSPR_INHERIT_FDS=%s" % (os.environ['NSPR_INHERIT_FDS']));
1043
1044 self.oVBoxSvcProcess = base.Process.spawn(sVBoxSVC, sVBoxSVC, '--auto-shutdown'); # SIGUSR1 requirement.
1045 try: # Try make sure we get the SIGINT and not VBoxSVC.
1046 os.setpgid(self.oVBoxSvcProcess.getPid(), 0); # pylint: disable=E1101
1047 os.setpgid(0, 0); # pylint: disable=E1101
1048 except:
1049 reporter.logXcpt();
1050
1051 os.close(iPipeW);
1052 try:
1053 sResponse = os.read(iPipeR, 32);
1054 except:
1055 reporter.logXcpt();
1056 sResponse = None;
1057 os.close(iPipeR);
1058
1059 if sResponse is None or sResponse.strip() != 'READY':
1060 reporter.error('VBoxSVC failed starting up... (sResponse=%s)' % (sResponse,));
1061 if not self.oVBoxSvcProcess.wait(5000):
1062 self.oVBoxSvcProcess.terminate(2500);
1063 self.oVBoxSvcProcess.wait(5000);
1064 self.oVBoxSvcProcess = None;
1065
1066 elif self.sHost == 'win':
1067 #
1068 # Windows - Just fudge it for now.
1069 #
1070 cMsFudge = 2000;
1071 self.oVBoxSvcProcess = base.Process.spawn(sVBoxSVC, sVBoxSVC);
1072
1073 else:
1074 reporter.error('Port me!');
1075
1076 #
1077 # Enable automatic crash reporting if we succeeded.
1078 #
1079 if self.oVBoxSvcProcess is not None:
1080 self.oVBoxSvcProcess.enableCrashReporting('crash/report/svc', 'crash/dump/svc');
1081
1082 #
1083 # Fudge and pid file.
1084 #
1085 if self.oVBoxSvcProcess != None and not self.oVBoxSvcProcess.wait(cMsFudge):
1086 if fWritePidFile:
1087 iPid = self.oVBoxSvcProcess.getPid();
1088 try:
1089 oFile = utils.openNoInherit(self.sVBoxSvcPidFile, "w+");
1090 oFile.write('%s' % (iPid,));
1091 oFile.close();
1092 except:
1093 reporter.logXcpt('sPidFile=%s' % (self.sVBoxSvcPidFile,));
1094 reporter.log('VBoxSVC PID=%u' % (iPid,));
1095
1096 #
1097 # Finally add the task so we'll notice when it dies in a relatively timely manner.
1098 #
1099 self.addTask(self.oVBoxSvcProcess);
1100 else:
1101 self.oVBoxSvcProcess = None;
1102 try: os.remove(self.sVBoxSvcPidFile);
1103 except: pass;
1104
1105 return self.oVBoxSvcProcess != None;
1106
1107
1108 def _killVBoxSVCByPidFile(self, sPidFile):
1109 """ Kill a VBoxSVC given the pid from it's pid file. """
1110
1111 # Read the pid file.
1112 if not os.path.isfile(sPidFile):
1113 return False;
1114 try:
1115 oFile = utils.openNoInherit(sPidFile, "r");
1116 sPid = oFile.readline().strip();
1117 oFile.close();
1118 except:
1119 reporter.logXcpt('sPidfile=%s' % (sPidFile,));
1120 return False;
1121
1122 # Convert the pid to an integer and validate the range a little bit.
1123 try:
1124 iPid = long(sPid);
1125 except:
1126 reporter.logXcpt('sPidfile=%s sPid="%s"' % (sPidFile, sPid));
1127 return False;
1128 if iPid <= 0:
1129 reporter.log('negative pid - sPidfile=%s sPid="%s" iPid=%d' % (sPidFile, sPid, iPid));
1130 return False;
1131
1132 # Take care checking that it's VBoxSVC we're about to inhume.
1133 if base.processCheckPidAndName(iPid, "VBoxSVC") is not True:
1134 reporter.log('Ignoring stale VBoxSVC pid file (pid=%s)' % (iPid,));
1135 return False;
1136
1137 # Loop thru our different ways of getting VBoxSVC to terminate.
1138 for aHow in [ [ base.sendUserSignal1, 5000, 'Dropping VBoxSVC a SIGUSR1 hint...'], \
1139 [ base.processInterrupt, 5000, 'Dropping VBoxSVC a SIGINT hint...'], \
1140 [ base.processTerminate, 7500, 'VBoxSVC is still around, killing it...'] ]:
1141 reporter.log(aHow[2]);
1142 if aHow[0](iPid) is True:
1143 msStart = base.timestampMilli();
1144 while base.timestampMilli() - msStart < 5000 \
1145 and base.processExists(iPid):
1146 time.sleep(0.2);
1147
1148 fRc = not base.processExists(iPid);
1149 if fRc is True:
1150 break;
1151 if fRc:
1152 reporter.log('Successfully killed VBoxSVC (pid=%s)' % (iPid,));
1153 else:
1154 reporter.log('Failed to kill VBoxSVC (pid=%s)' % (iPid,));
1155 return fRc;
1156
1157 def _stopVBoxSVC(self):
1158 """
1159 Stops VBoxSVC. Try the polite way first.
1160 """
1161
1162 if self.oVBoxSvcProcess:
1163 self.removeTask(self.oVBoxSvcProcess);
1164 self.oVBoxSvcProcess.enableCrashReporting(None, None); # Disables it.
1165
1166 fRc = False;
1167 if self.oVBoxSvcProcess is not None \
1168 and not self.fVBoxSvcInDebugger:
1169 # by process object.
1170 if self.oVBoxSvcProcess.isRunning():
1171 reporter.log('Dropping VBoxSVC a SIGUSR1 hint...');
1172 if not self.oVBoxSvcProcess.sendUserSignal1() \
1173 or not self.oVBoxSvcProcess.wait(5000):
1174 reporter.log('Dropping VBoxSVC a SIGINT hint...');
1175 if not self.oVBoxSvcProcess.interrupt() \
1176 or not self.oVBoxSvcProcess.wait(5000):
1177 reporter.log('VBoxSVC is still around, killing it...');
1178 self.oVBoxSvcProcess.terminate();
1179 self.oVBoxSvcProcess.wait(7500);
1180 else:
1181 reporter.log('VBoxSVC is no longer running...');
1182 if not self.oVBoxSvcProcess.isRunning():
1183 self.oVBoxSvcProcess = None;
1184 else:
1185 # by pid file.
1186 self._killVBoxSVCByPidFile('%s/VBoxSVC.pid' % (self.sScratchPath,));
1187 return fRc;
1188
1189 def _setupVBoxApi(self):
1190 """
1191 Import and set up the vboxapi.
1192 The caller saves and restores sys.path.
1193 """
1194
1195 # Setup vbox logging for self (the test driver).
1196 self.sSelfLogFile = '%s/VBoxTestDriver.log' % (self.sScratchPath,);
1197 try: os.remove(self.sSelfLogFile);
1198 except: pass;
1199 os.environ['VBOX_LOG'] = self.sLogSelfGroups;
1200 os.environ['VBOX_LOG_FLAGS'] = '%s append' % (self.sLogSelfFlags, );
1201 if self.sLogSelfDest:
1202 os.environ['VBOX_LOG_DEST'] = self.sLogSelfDest;
1203 else:
1204 os.environ['VBOX_LOG_DEST'] = 'file=%s' % (self.sSelfLogFile,);
1205 os.environ['VBOX_RELEASE_LOG_FLAGS'] = 'time append';
1206
1207 # Hack the sys.path + environment so the vboxapi can be found.
1208 sys.path.insert(0, self.oBuild.sInstallPath);
1209 if self.oBuild.sSdkPath is not None:
1210 sys.path.insert(0, os.path.join(self.oBuild.sSdkPath, 'installer'))
1211 sys.path.insert(1, os.path.join(self.oBuild.sSdkPath, 'bindings', 'xpcom', 'python'))
1212 os.environ['VBOX_PROGRAM_PATH'] = self.oBuild.sInstallPath;
1213 reporter.log("sys.path: %s" % (sys.path));
1214
1215 try:
1216 # pylint: disable=F0401
1217 from vboxapi import VirtualBoxManager
1218 if self.sHost == 'win':
1219 from pythoncom import com_error as NativeComExceptionClass # pylint: disable=E0611
1220 import winerror as NativeComErrorClass
1221 else:
1222 from xpcom import Exception as NativeComExceptionClass
1223 from xpcom import nsError as NativeComErrorClass
1224 # pylint: enable=F0401
1225 except:
1226 traceback.print_exc();
1227 return False;
1228
1229 __deployExceptionHacks__(NativeComExceptionClass)
1230 ComError.copyErrors(NativeComErrorClass);
1231
1232 # Create the manager.
1233 try:
1234 self.oVBoxMgr = VirtualBoxManager(None, None)
1235 except:
1236 self.oVBoxMgr = None;
1237 reporter.logXcpt('VirtualBoxManager exception');
1238 return False;
1239
1240 # Figure the API version.
1241 try:
1242 oVBox = self.oVBoxMgr.getVirtualBox();
1243 try:
1244 sVer = oVBox.version;
1245 except:
1246 reporter.logXcpt('Failed to get VirtualBox version, assuming 4.0.0');
1247 sVer = "4.0.0";
1248 if sVer.startswith("4.4") or (sVer.startswith("4.3.5") and len(sVer) == 6):
1249 self.fpApiVer = 4.4;
1250 elif sVer.startswith("4.3") or (sVer.startswith("4.2.5") and len(sVer) == 6):
1251 self.fpApiVer = 4.3;
1252 elif sVer.startswith("4.2."):
1253 self.fpApiVer = 4.2; ## @todo Fudge: Add (proper) 4.2 API support. Unmount medium etc?
1254 elif sVer.startswith("4.1.") or (sVer.startswith("4.0.5") and len(sVer) == 6):
1255 self.fpApiVer = 4.1;
1256 elif sVer.startswith("4.0."):
1257 self.fpApiVer = 4.0;
1258 elif sVer.startswith("3.2."):
1259 self.fpApiVer = 3.2;
1260 elif sVer.startswith("3.1."):
1261 self.fpApiVer = 3.1;
1262 elif sVer.startswith("3.0."):
1263 self.fpApiVer = 3.0;
1264 else:
1265 raise base.GenError('Unknown version "%s"' % (sVer,));
1266
1267 self._patchVBoxMgr();
1268
1269 from testdriver.vboxwrappers import VirtualBoxWrapper;
1270 self.oVBox = VirtualBoxWrapper(oVBox, self.oVBoxMgr, self.fpApiVer, self);
1271 vboxcon.goHackModuleClass.oVBoxMgr = self.oVBoxMgr; # VBoxConstantWrappingHack.
1272 vboxcon.fpApiVer = self.fpApiVer
1273 self.fImportedVBoxApi = True;
1274 reporter.log('Found version %s (%s)' % (self.fpApiVer, sVer));
1275 except:
1276 self.oVBoxMgr = None;
1277 self.oVBox = None;
1278 reporter.logXcpt("getVirtualBox exception");
1279 return False;
1280 return True;
1281
1282 def _patchVBoxMgr(self):
1283 """
1284 Glosses over missing self.oVBoxMgr methods on older VBox versions.
1285 """
1286
1287 def _xcptGetResult(oSelf, oXcpt = None):
1288 """ See vboxapi. """
1289 _ = oSelf;
1290 if oXcpt is None: oXcpt = sys.exc_info()[1];
1291 if sys.platform == 'win32':
1292 import winerror; # pylint: disable=F0401
1293 hrXcpt = oXcpt.hresult;
1294 if hrXcpt == winerror.DISP_E_EXCEPTION:
1295 hrXcpt = oXcpt.excepinfo[5];
1296 else:
1297 hrXcpt = oXcpt.error;
1298 return hrXcpt;
1299
1300 def _xcptIsDeadInterface(oSelf, oXcpt = None):
1301 """ See vboxapi. """
1302 return oSelf.xcptGetStatus(oXcpt) in [
1303 0x80004004, -2147467260, # NS_ERROR_ABORT
1304 0x800706be, -2147023170, # NS_ERROR_CALL_FAILED (RPC_S_CALL_FAILED)
1305 0x800706ba, -2147023174, # RPC_S_SERVER_UNAVAILABLE.
1306 0x800706be, -2147023170, # RPC_S_CALL_FAILED.
1307 0x800706bf, -2147023169, # RPC_S_CALL_FAILED_DNE.
1308 0x80010108, -2147417848, # RPC_E_DISCONNECTED.
1309 0x800706b5, -2147023179, # RPC_S_UNKNOWN_IF
1310 ];
1311
1312 def _xcptIsOurXcptKind(oSelf, oXcpt = None):
1313 """ See vboxapi. """
1314 _ = oSelf;
1315 if oXcpt is None: oXcpt = sys.exc_info()[1];
1316 if sys.platform == 'win32':
1317 from pythoncom import com_error as NativeComExceptionClass # pylint: disable=F0401,E0611
1318 else:
1319 from xpcom import Exception as NativeComExceptionClass # pylint: disable=F0401
1320 return isinstance(oXcpt, NativeComExceptionClass);
1321
1322 def _xcptIsEqual(oSelf, oXcpt, hrStatus):
1323 """ See vboxapi. """
1324 hrXcpt = oSelf.xcptGetResult(oXcpt);
1325 return hrXcpt == hrStatus or hrXcpt == hrStatus - 0x100000000;
1326
1327 def _xcptToString(oSelf, oXcpt):
1328 """ See vboxapi. """
1329 _ = oSelf;
1330 if oXcpt is None: oXcpt = sys.exc_info()[1];
1331 return str(oXcpt);
1332
1333 # Add utilities found in newer vboxapi revision.
1334 if not hasattr(self.oVBoxMgr, 'xcptIsDeadInterface'):
1335 import types;
1336 self.oVBoxMgr.xcptGetResult = types.MethodType(_xcptGetResult, self.oVBoxMgr);
1337 self.oVBoxMgr.xcptIsDeadInterface = types.MethodType(_xcptIsDeadInterface, self.oVBoxMgr);
1338 self.oVBoxMgr.xcptIsOurXcptKind = types.MethodType(_xcptIsOurXcptKind, self.oVBoxMgr);
1339 self.oVBoxMgr.xcptIsEqual = types.MethodType(_xcptIsEqual, self.oVBoxMgr);
1340 self.oVBoxMgr.xcptToString = types.MethodType(_xcptToString, self.oVBoxMgr);
1341
1342
1343 def _teardownVBoxApi(self):
1344 """
1345 Drop all VBox object references and shutdown com/xpcom.
1346 """
1347 if not self.fImportedVBoxApi:
1348 return True;
1349
1350 self.aoRemoteSessions = [];
1351 self.aoVMs = [];
1352 self.oVBoxMgr = None;
1353 self.oVBox = None;
1354
1355 try:
1356 import gc
1357 gc.collect();
1358 except:
1359 reporter.logXcpt();
1360 self.fImportedVBoxApi = False;
1361
1362 if self.sHost == 'win':
1363 pass; ## TODO shutdown COM if possible/necessary?
1364 else:
1365 try:
1366 from xpcom import _xpcom as _xpcom; # pylint: disable=F0401
1367 hrc = _xpcom.NS_ShutdownXPCOM();
1368 cIfs = _xpcom._GetInterfaceCount(); # pylint: disable=W0212
1369 cObjs = _xpcom._GetGatewayCount(); # pylint: disable=W0212
1370 if cObjs == 0 and cIfs == 0:
1371 reporter.log('actionCleanupAfter: NS_ShutdownXPCOM -> %s, nothing left behind.' % (hrc, ));
1372 else:
1373 reporter.log('actionCleanupAfter: NS_ShutdownXPCOM -> %s, leaving %s objects and %s interfaces behind...' \
1374 % (hrc, cObjs, cIfs));
1375 if hasattr(_xpcom, '_DumpInterfaces'):
1376 try:
1377 _xpcom._DumpInterfaces(); # pylint: disable=W0212
1378 except:
1379 reporter.logXcpt('actionCleanupAfter: _DumpInterfaces failed');
1380 except:
1381 reporter.logXcpt();
1382
1383 try:
1384 gc.collect();
1385 time.sleep(0.5); # fudge factory
1386 except:
1387 reporter.logXcpt();
1388 return True;
1389
1390 def _powerOffAllVms(self):
1391 """
1392 Tries to power off all running VMs.
1393 """
1394 for oSession in self.aoRemoteSessions:
1395 uPid = oSession.getPid();
1396 if uPid is not None:
1397 reporter.log('_powerOffAllVms: PID is %s for %s, trying to kill it.' % (uPid, oSession.sName,));
1398 base.processKill(uPid);
1399 else:
1400 reporter.log('_powerOffAllVms: No PID for %s' % (oSession.sName,));
1401 oSession.close();
1402 return None;
1403
1404
1405
1406 #
1407 # Build type, OS and arch getters.
1408 #
1409
1410 def getBuildType(self):
1411 """
1412 Get the build type.
1413 """
1414 if not self._detectBuild():
1415 return 'release';
1416 return self.oBuild.sType;
1417
1418 def getBuildOs(self):
1419 """
1420 Get the build OS.
1421 """
1422 if not self._detectBuild():
1423 return self.sHost;
1424 return self.oBuild.sOs;
1425
1426 def getBuildArch(self):
1427 """
1428 Get the build arch.
1429 """
1430 if not self._detectBuild():
1431 return self.sHostArch;
1432 return self.oBuild.sArch;
1433
1434 def getGuestAdditionsIso(self):
1435 """
1436 Get the path to the guest addition iso.
1437 """
1438 if not self._detectBuild():
1439 return None;
1440 return self.oBuild.sGuestAdditionsIso;
1441
1442 #
1443 # Override everything from the base class so the testdrivers don't have to
1444 # check whether we have overridden a method or not.
1445 #
1446
1447 def showUsage(self):
1448 rc = base.TestDriver.showUsage(self);
1449 reporter.log('');
1450 reporter.log('Generic VirtualBox Options:');
1451 reporter.log(' --vbox-session-type <type>');
1452 reporter.log(' Sets the session type. Typical values are: gui, headless, sdl');
1453 reporter.log(' Default: %s' % (self.sSessionTypeDef));
1454 reporter.log(' --vrdp, --no-vrdp');
1455 reporter.log(' Enables VRDP, ports starting at 6000');
1456 reporter.log(' Default: --vrdp');
1457 reporter.log(' --vrdp-base-port <port>');
1458 reporter.log(' Sets the base for VRDP port assignments.');
1459 reporter.log(' Default: %s' % (self.uVrdpBasePortDef));
1460 reporter.log(' --vbox-default-bridged-nic <interface>');
1461 reporter.log(' Sets the default interface for bridged networking.');
1462 reporter.log(' Default: autodetect');
1463 reporter.log(' --vbox-use-svc-defaults');
1464 reporter.log(' Use default locations and files for VBoxSVC. This is useful');
1465 reporter.log(' for automatically configuring the test VMs for debugging.');
1466 reporter.log(' --vbox-self-log');
1467 reporter.log(' The VBox logger group settings for the testdriver.');
1468 reporter.log(' --vbox-self-log-flags');
1469 reporter.log(' The VBox logger flags settings for the testdriver.');
1470 reporter.log(' --vbox-self-log-dest');
1471 reporter.log(' The VBox logger destination settings for the testdriver.');
1472 reporter.log(' --vbox-session-log');
1473 reporter.log(' The VM session logger group settings.');
1474 reporter.log(' --vbox-session-log-flags');
1475 reporter.log(' The VM session logger flags.');
1476 reporter.log(' --vbox-session-log-dest');
1477 reporter.log(' The VM session logger destination settings.');
1478 reporter.log(' --vbox-svc-log');
1479 reporter.log(' The VBoxSVC logger group settings.');
1480 reporter.log(' --vbox-svc-log-flags');
1481 reporter.log(' The VBoxSVC logger flag settings.');
1482 reporter.log(' --vbox-svc-log-dest');
1483 reporter.log(' The VBoxSVC logger destination settings.');
1484 reporter.log(' --vbox-log');
1485 reporter.log(' The VBox logger group settings for everyone.');
1486 reporter.log(' --vbox-log-flags');
1487 reporter.log(' The VBox logger flags settings for everyone.');
1488 reporter.log(' --vbox-log-dest');
1489 reporter.log(' The VBox logger destination settings for everyone.');
1490 reporter.log(' --vbox-svc-debug');
1491 reporter.log(' Start VBoxSVC in a debugger');
1492 reporter.log(' --vbox-always-upload-logs');
1493 reporter.log(' Whether to always upload log files, or only do so on failure.');
1494 reporter.log(' --vbox-always-upload-screenshots');
1495 reporter.log(' Whether to always upload final screen shots, or only do so on failure.');
1496 if self.oTestVmSet is not None:
1497 self.oTestVmSet.showUsage();
1498 return rc;
1499
1500 def parseOption(self, asArgs, iArg): # pylint: disable=R0915
1501 if asArgs[iArg] == '--vbox-session-type':
1502 iArg += 1;
1503 if iArg >= len(asArgs):
1504 raise base.InvalidOption('The "--vbox-session-type" takes an argument');
1505 self.sSessionType = asArgs[iArg];
1506 elif asArgs[iArg] == '--vrdp':
1507 self.fEnableVrdp = True;
1508 elif asArgs[iArg] == '--no-vrdp':
1509 self.fEnableVrdp = False;
1510 elif asArgs[iArg] == '--vrdp-base-port':
1511 iArg += 1;
1512 if iArg >= len(asArgs):
1513 raise base.InvalidOption('The "--vrdp-base-port" takes an argument');
1514 try: self.uVrdpBasePort = int(asArgs[iArg]);
1515 except: raise base.InvalidOption('The "--vrdp-base-port" value "%s" is not a valid integer', asArgs[iArg]);
1516 if self.uVrdpBasePort <= 0 or self.uVrdpBasePort >= 65530:
1517 raise base.InvalidOption('The "--vrdp-base-port" value "%s" is not in the valid range (1..65530)', asArgs[iArg]);
1518 elif asArgs[iArg] == '--vbox-default-bridged-nic':
1519 iArg += 1;
1520 if iArg >= len(asArgs):
1521 raise base.InvalidOption('The "--vbox-default-bridged-nic" takes an argument');
1522 self.sDefBridgedNic = asArgs[iArg];
1523 elif asArgs[iArg] == '--vbox-use-svc-defaults':
1524 self.fUseDefaultSvc = True;
1525 elif asArgs[iArg] == '--vbox-self-log':
1526 iArg += 1;
1527 if iArg >= len(asArgs):
1528 raise base.InvalidOption('The "--vbox-self-log" takes an argument');
1529 self.sLogSelfGroups = asArgs[iArg];
1530 elif asArgs[iArg] == '--vbox-self-log-flags':
1531 iArg += 1;
1532 if iArg >= len(asArgs):
1533 raise base.InvalidOption('The "--vbox-self-log-flags" takes an argument');
1534 self.sLogSelfFlags = asArgs[iArg];
1535 elif asArgs[iArg] == '--vbox-self-log-dest':
1536 iArg += 1;
1537 if iArg >= len(asArgs):
1538 raise base.InvalidOption('The "--vbox-self-log-dest" takes an argument');
1539 self.sLogSelfDest = asArgs[iArg];
1540 elif asArgs[iArg] == '--vbox-session-log':
1541 iArg += 1;
1542 if iArg >= len(asArgs):
1543 raise base.InvalidOption('The "--vbox-session-log" takes an argument');
1544 self.sLogSessionGroups = asArgs[iArg];
1545 elif asArgs[iArg] == '--vbox-session-log-flags':
1546 iArg += 1;
1547 if iArg >= len(asArgs):
1548 raise base.InvalidOption('The "--vbox-session-log-flags" takes an argument');
1549 self.sLogSessionFlags = asArgs[iArg];
1550 elif asArgs[iArg] == '--vbox-session-log-dest':
1551 iArg += 1;
1552 if iArg >= len(asArgs):
1553 raise base.InvalidOption('The "--vbox-session-log-dest" takes an argument');
1554 self.sLogSessionDest = asArgs[iArg];
1555 elif asArgs[iArg] == '--vbox-svc-log':
1556 iArg += 1;
1557 if iArg >= len(asArgs):
1558 raise base.InvalidOption('The "--vbox-svc-log" takes an argument');
1559 self.sLogSvcGroups = asArgs[iArg];
1560 elif asArgs[iArg] == '--vbox-svc-log-flags':
1561 iArg += 1;
1562 if iArg >= len(asArgs):
1563 raise base.InvalidOption('The "--vbox-svc-log-flags" takes an argument');
1564 self.sLogSvcFlags = asArgs[iArg];
1565 elif asArgs[iArg] == '--vbox-svc-log-dest':
1566 iArg += 1;
1567 if iArg >= len(asArgs):
1568 raise base.InvalidOption('The "--vbox-svc-log-dest" takes an argument');
1569 self.sLogSvcDest = asArgs[iArg];
1570 elif asArgs[iArg] == '--vbox-log':
1571 iArg += 1;
1572 if iArg >= len(asArgs):
1573 raise base.InvalidOption('The "--vbox-log" takes an argument');
1574 self.sLogSelfGroups = asArgs[iArg];
1575 self.sLogSessionGroups = asArgs[iArg];
1576 self.sLogSvcGroups = asArgs[iArg];
1577 elif asArgs[iArg] == '--vbox-log-flags':
1578 iArg += 1;
1579 if iArg >= len(asArgs):
1580 raise base.InvalidOption('The "--vbox-svc-flags" takes an argument');
1581 self.sLogSelfFlags = asArgs[iArg];
1582 self.sLogSessionFlags = asArgs[iArg];
1583 self.sLogSvcFlags = asArgs[iArg];
1584 elif asArgs[iArg] == '--vbox-log-dest':
1585 iArg += 1;
1586 if iArg >= len(asArgs):
1587 raise base.InvalidOption('The "--vbox-log-dest" takes an argument');
1588 self.sLogSelfDest = asArgs[iArg];
1589 self.sLogSessionDest = asArgs[iArg];
1590 self.sLogSvcDest = asArgs[iArg];
1591 elif asArgs[iArg] == '--vbox-svc-debug':
1592 self.fVBoxSvcInDebugger = True;
1593 elif asArgs[iArg] == '--vbox-always-upload-logs':
1594 self.fAlwaysUploadLogs = True;
1595 elif asArgs[iArg] == '--vbox-always-upload-screenshots':
1596 self.fAlwaysUploadScreenshots = True;
1597 else:
1598 # Relevant for selecting VMs to test?
1599 if self.oTestVmSet is not None:
1600 iRc = self.oTestVmSet.parseOption(asArgs, iArg);
1601 if iRc != iArg:
1602 return iRc;
1603
1604 # Hand it to the base class.
1605 return base.TestDriver.parseOption(self, asArgs, iArg);
1606 return iArg + 1;
1607
1608 def completeOptions(self):
1609 return base.TestDriver.completeOptions(self);
1610
1611 def getResourceSet(self):
1612 if self.oTestVmSet is not None:
1613 return self.oTestVmSet.getResourceSet();
1614 return base.TestDriver.getResourceSet(self);
1615
1616 def actionExtract(self):
1617 return base.TestDriver.actionExtract(self);
1618
1619 def actionVerify(self):
1620 return base.TestDriver.actionVerify(self);
1621
1622 def actionConfig(self):
1623 return base.TestDriver.actionConfig(self);
1624
1625 def actionExecute(self):
1626 return base.TestDriver.actionExecute(self);
1627
1628 def actionCleanupBefore(self):
1629 """
1630 Kill any VBoxSVC left behind by a previous test run.
1631 """
1632 self._killVBoxSVCByPidFile('%s/VBoxSVC.pid' % (self.sScratchPath,));
1633 return base.TestDriver.actionCleanupBefore(self);
1634
1635 def actionCleanupAfter(self):
1636 """
1637 Clean up the VBox bits and then call the base driver.
1638
1639 If your test driver overrides this, it should normally call us at the
1640 end of the job.
1641 """
1642
1643 # Kill any left over VM processes.
1644 self._powerOffAllVms();
1645
1646 # Drop all VBox object references and shutdown xpcom then
1647 # terminating VBoxSVC, with extreme prejudice if need be.
1648 self._teardownVBoxApi();
1649 self._stopVBoxSVC();
1650
1651 # Add the VBoxSVC and testdriver debug+release log files.
1652 if self.fAlwaysUploadLogs or reporter.getErrorCount() > 0:
1653 if self.sVBoxSvcLogFile is not None and os.path.isfile(self.sVBoxSvcLogFile):
1654 reporter.addLogFile(self.sVBoxSvcLogFile, 'log/debug/svc', 'Debug log file for VBoxSVC');
1655 self.sVBoxSvcLogFile = None;
1656
1657 if self.sSelfLogFile is not None and os.path.isfile(self.sSelfLogFile):
1658 reporter.addLogFile(self.sSelfLogFile, 'log/debug/client', 'Debug log file for the test driver');
1659 self.sSelfLogFile = None;
1660
1661 sVBoxSvcRelLog = os.path.join(self.sScratchPath, 'VBoxUserHome', 'VBoxSVC.log');
1662 if os.path.isfile(sVBoxSvcRelLog):
1663 reporter.addLogFile(sVBoxSvcRelLog, 'log/release/svc', 'Release log file for VBoxSVC');
1664 for sSuff in [ '.1', '.2', '.3', '.4', '.5', '.6', '.7', '.8' ]:
1665 if os.path.isfile(sVBoxSvcRelLog + sSuff):
1666 reporter.addLogFile(sVBoxSvcRelLog + sSuff, 'log/release/svc', 'Release log file for VBoxSVC');
1667 # Testbox debugging - START - TEMPORARY, REMOVE ASAP.
1668 if self.sHost in ('darwin', 'freebsd', 'linux', 'solaris', ):
1669 try:
1670 print '> ls -la %s' % (os.path.join(self.sScratchPath, 'VBoxUserHome'),);
1671 utils.processCall(['ls', '-la', os.path.join(self.sScratchPath, 'VBoxUserHome')]);
1672 print '> ls -la %s' % (self.sScratchPath,);
1673 utils.processCall(['ls', '-la', self.sScratchPath]);
1674 except: pass;
1675 # Testbox debugging - END - TEMPORARY, REMOVE ASAP.
1676
1677 # Finally, call the base driver to wipe the scratch space.
1678 return base.TestDriver.actionCleanupAfter(self);
1679
1680 def actionAbort(self):
1681 """
1682 Terminate VBoxSVC if we've got a pid file.
1683 """
1684 self._killVBoxSVCByPidFile('%s/VBoxSVC.pid' % (self.sScratchPath,));
1685 return base.TestDriver.actionAbort(self);
1686
1687 def onExit(self, iRc):
1688 """
1689 Stop VBoxSVC if we've started it.
1690 """
1691 if self.oVBoxSvcProcess is not None:
1692 reporter.log('*** Shutting down the VBox API... (iRc=%s)' % (iRc,));
1693 self._powerOffAllVms();
1694 self._teardownVBoxApi();
1695 self._stopVBoxSVC();
1696 reporter.log('*** VBox API shutdown done.');
1697 return base.TestDriver.onExit(self, iRc);
1698
1699
1700 #
1701 # Task wait method override.
1702 #
1703
1704 def notifyAboutReadyTask(self, oTask):
1705 """
1706 Overriding base.TestDriver.notifyAboutReadyTask.
1707 """
1708 try:
1709 self.oVBoxMgr.interruptWaitEvents();
1710 reporter.log2('vbox.notifyAboutReadyTask: called interruptWaitEvents');
1711 except:
1712 reporter.logXcpt('vbox.notifyAboutReadyTask');
1713 return base.TestDriver.notifyAboutReadyTask(self, oTask);
1714
1715 def waitForTasksSleepWorker(self, cMsTimeout):
1716 """
1717 Overriding base.TestDriver.waitForTasksSleepWorker.
1718 """
1719 try:
1720 rc = self.oVBoxMgr.waitForEvents(int(cMsTimeout));
1721 _ = rc; #reporter.log2('vbox.waitForTasksSleepWorker(%u): true (waitForEvents -> %s)' % (cMsTimeout, rc));
1722 return True;
1723 except KeyboardInterrupt:
1724 raise;
1725 except:
1726 reporter.logXcpt('vbox.waitForTasksSleepWorker');
1727 return False;
1728
1729 #
1730 # Utility methods.
1731 #
1732
1733 def processEvents(self, cMsTimeout = 0):
1734 """
1735 Processes events, returning after the first batch has been processed
1736 or the time limit has been reached.
1737
1738 Only Ctrl-C exception, no return.
1739 """
1740 try:
1741 self.oVBoxMgr.waitForEvents(cMsTimeout);
1742 except KeyboardInterrupt:
1743 raise;
1744 except:
1745 pass;
1746 return None;
1747
1748 def processPendingEvents(self):
1749 """ processEvents(0) - no waiting. """
1750 return self.processEvents(0);
1751
1752 def sleep(self, cSecs):
1753 """
1754 Sleep for a specified amount of time, processing XPCOM events all the while.
1755 """
1756 cMsTimeout = long(cSecs * 1000);
1757 msStart = base.timestampMilli();
1758 self.processEvents(0);
1759 while True:
1760 cMsElapsed = base.timestampMilli() - msStart;
1761 if cMsElapsed > cMsTimeout:
1762 break;
1763 #reporter.log2('cMsTimeout=%s - cMsElapsed=%d => %s' % (cMsTimeout, cMsElapsed, cMsTimeout - cMsElapsed));
1764 self.processEvents(cMsTimeout - cMsElapsed);
1765 return None;
1766
1767 def _logVmInfoUnsafe(self, oVM): # pylint: disable=R0915,R0912
1768 """
1769 Internal worker for logVmInfo that is wrapped in try/except.
1770
1771 This is copy, paste, search, replace and edit of infoCmd from vboxshell.py.
1772 """
1773 oOsType = self.oVBox.getGuestOSType(oVM.OSTypeId)
1774 reporter.log(" Name: %s" % (oVM.name));
1775 reporter.log(" ID: %s" % (oVM.id));
1776 reporter.log(" OS Type: %s - %s" % (oVM.OSTypeId, oOsType.description));
1777 reporter.log(" Machine state: %s" % (oVM.state));
1778 reporter.log(" Session state: %s" % (oVM.sessionState));
1779 if self.fpApiVer >= 4.2:
1780 reporter.log(" Session PID: %u (%#x)" % (oVM.sessionPID, oVM.sessionPID));
1781 else:
1782 reporter.log(" Session PID: %u (%#x)" % (oVM.sessionPid, oVM.sessionPid));
1783 reporter.log(" Session Type: %s" % (oVM.sessionType));
1784 reporter.log(" CPUs: %s" % (oVM.CPUCount));
1785 reporter.log(" RAM: %sMB" % (oVM.memorySize));
1786 reporter.log(" VRAM: %sMB" % (oVM.VRAMSize));
1787 reporter.log(" Monitors: %s" % (oVM.monitorCount));
1788 reporter.log(" Firmware: %s" % (oVM.firmwareType));
1789 reporter.log(" HwVirtEx: %s" % (oVM.getHWVirtExProperty(vboxcon.HWVirtExPropertyType_Enabled)));
1790 reporter.log(" VPID support: %s" % (oVM.getHWVirtExProperty(vboxcon.HWVirtExPropertyType_VPID)));
1791 reporter.log(" Nested paging: %s" % (oVM.getHWVirtExProperty(vboxcon.HWVirtExPropertyType_NestedPaging)));
1792 if self.fpApiVer >= 4.2 and hasattr(vboxcon, 'CPUPropertyType_LongMode'):
1793 reporter.log(" Long-mode: %s" % (oVM.getCPUProperty(vboxcon.CPUPropertyType_LongMode)));
1794 if self.fpApiVer >= 3.2:
1795 reporter.log(" PAE: %s" % (oVM.getCPUProperty(vboxcon.CPUPropertyType_PAE)));
1796 reporter.log(" Synthetic CPU: %s" % (oVM.getCPUProperty(vboxcon.CPUPropertyType_Synthetic)));
1797 else:
1798 reporter.log(" PAE: %s" % (oVM.getCpuProperty(vboxcon.CpuPropertyType_PAE)));
1799 reporter.log(" Synthetic CPU: %s" % (oVM.getCpuProperty(vboxcon.CpuPropertyType_Synthetic)));
1800 reporter.log(" ACPI: %s" % (oVM.BIOSSettings.ACPIEnabled));
1801 reporter.log(" IO-APIC: %s" % (oVM.BIOSSettings.IOAPICEnabled));
1802 if self.fpApiVer >= 3.2:
1803 if self.fpApiVer >= 4.2:
1804 reporter.log(" HPET: %s" % (oVM.HPETEnabled));
1805 else:
1806 reporter.log(" HPET: %s" % (oVM.hpetEnabled));
1807 reporter.log(" 3D acceleration: %s" % (oVM.accelerate3DEnabled));
1808 reporter.log(" 2D acceleration: %s" % (oVM.accelerate2DVideoEnabled));
1809 reporter.log(" TeleporterEnabled: %s" % (oVM.teleporterEnabled));
1810 reporter.log(" TeleporterPort: %s" % (oVM.teleporterPort));
1811 reporter.log(" TeleporterAddress: %s" % (oVM.teleporterAddress));
1812 reporter.log(" TeleporterPassword: %s" % (oVM.teleporterPassword));
1813 reporter.log(" Clipboard mode: %s" % (oVM.clipboardMode));
1814 if self.fpApiVer >= 4.0:
1815 reporter.log(" VRDP server: %s" % (oVM.VRDEServer.enabled));
1816 try: sPorts = oVM.VRDEServer.getVRDEProperty("TCP/Ports");
1817 except: sPorts = "";
1818 reporter.log(" VRDP server ports: %s" % (sPorts));
1819 reporter.log(" VRDP auth: %s (%s)" % (oVM.VRDEServer.authType, oVM.VRDEServer.authLibrary));
1820 else:
1821 reporter.log(" VRDP server: %s" % (oVM.VRDPServer.enabled));
1822 reporter.log(" VRDP server ports: %s" % (oVM.VRDPServer.ports));
1823 reporter.log(" Last changed: %s" % (oVM.lastStateChange));
1824
1825 aoControllers = self.oVBoxMgr.getArray(oVM, 'storageControllers')
1826 if aoControllers:
1827 reporter.log(" Controllers:");
1828 for oCtrl in aoControllers:
1829 reporter.log(" %s %s bus: %s type: %s" % (oCtrl.name, oCtrl.controllerType, oCtrl.bus, oCtrl.controllerType));
1830
1831 self.processPendingEvents();
1832 aoAttachments = self.oVBoxMgr.getArray(oVM, 'mediumAttachments')
1833 if aoAttachments:
1834 reporter.log(" Attachments:");
1835 for oAtt in aoAttachments:
1836 sCtrl = "Controller: %s port: %s device: %s type: %s" % (oAtt.controller, oAtt.port, oAtt.device, oAtt.type);
1837 oMedium = oAtt.medium
1838 if oAtt.type == vboxcon.DeviceType_HardDisk:
1839 reporter.log(" %s: HDD" % sCtrl);
1840 reporter.log(" Id: %s" % (oMedium.id));
1841 reporter.log(" Name: %s" % (oMedium.name));
1842 reporter.log(" Format: %s" % (oMedium.format));
1843 reporter.log(" Location: %s" % (oMedium.location));
1844
1845 if oAtt.type == vboxcon.DeviceType_DVD:
1846 reporter.log(" %s: DVD" % sCtrl);
1847 if oMedium:
1848 reporter.log(" Id: %s" % (oMedium.id));
1849 reporter.log(" Name: %s" % (oMedium.name));
1850 if oMedium.hostDrive:
1851 reporter.log(" Host DVD %s" % (oMedium.location));
1852 if oAtt.passthrough:
1853 reporter.log(" [passthrough mode]");
1854 else:
1855 reporter.log(" Virtual image: %s" % (oMedium.location));
1856 reporter.log(" Size: %s" % (oMedium.size));
1857 else:
1858 reporter.log(" empty");
1859
1860 if oAtt.type == vboxcon.DeviceType_Floppy:
1861 reporter.log(" %s: Floppy" % sCtrl);
1862 if oMedium:
1863 reporter.log(" Id: %s" % (oMedium.id));
1864 reporter.log(" Name: %s" % (oMedium.name));
1865 if oMedium.hostDrive:
1866 reporter.log(" Host floppy: %s" % (oMedium.location));
1867 else:
1868 reporter.log(" Virtual image: %s" % (oMedium.location));
1869 reporter.log(" Size: %s" % (oMedium.size));
1870 else:
1871 reporter.log(" empty");
1872 self.processPendingEvents();
1873
1874 reporter.log(" Network Adapter:");
1875 for iSlot in range(0, 32):
1876 try: oNic = oVM.getNetworkAdapter(iSlot)
1877 except: break;
1878 if not oNic.enabled:
1879 reporter.log2(" slot #%d found but not enabled, skipping" % (iSlot,));
1880 continue;
1881 if oNic.adapterType == vboxcon.NetworkAdapterType_Am79C973: sType = "PCNet";
1882 elif oNic.adapterType == vboxcon.NetworkAdapterType_Am79C970A: sType = "PCNetOld";
1883 elif oNic.adapterType == vboxcon.NetworkAdapterType_I82545EM: sType = "E1000";
1884 elif oNic.adapterType == vboxcon.NetworkAdapterType_I82540EM: sType = "E1000Desk";
1885 elif oNic.adapterType == vboxcon.NetworkAdapterType_I82543GC: sType = "E1000Srv2";
1886 elif oNic.adapterType == vboxcon.NetworkAdapterType_Virtio: sType = "Virtio";
1887 else: sType = "unknown %s" % (oNic.adapterType);
1888 reporter.log(" slot #%d: type: %s (%s) MAC Address: %s lineSpeed: %s" % \
1889 (iSlot, sType, oNic.adapterType, oNic.MACAddress, oNic.lineSpeed) );
1890
1891 if oNic.attachmentType == vboxcon.NetworkAttachmentType_NAT:
1892 reporter.log(" attachmentType: NAT (%s)" % (oNic.attachmentType));
1893 if self.fpApiVer >= 4.1:
1894 reporter.log(" nat-network: %s" % (oNic.NATNetwork,));
1895 elif oNic.attachmentType == vboxcon.NetworkAttachmentType_Bridged:
1896 reporter.log(" attachmentType: Bridged (%s)" % (oNic.attachmentType));
1897 if self.fpApiVer >= 4.1:
1898 reporter.log(" hostInterface: %s" % (oNic.bridgedInterface));
1899 else:
1900 reporter.log(" hostInterface: %s" % (oNic.hostInterface));
1901 elif oNic.attachmentType == vboxcon.NetworkAttachmentType_Internal:
1902 reporter.log(" attachmentType: Internal (%s)" % (oNic.attachmentType));
1903 reporter.log(" intnet-name: %s" % (oNic.internalNetwork,));
1904 elif oNic.attachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1905 reporter.log(" attachmentType: HostOnly (%s)" % (oNic.attachmentType));
1906 if self.fpApiVer >= 4.1:
1907 reporter.log(" hostInterface: %s" % (oNic.hostOnlyInterface));
1908 else:
1909 reporter.log(" hostInterface: %s" % (oNic.hostInterface));
1910 else:
1911 if self.fpApiVer >= 4.1:
1912 if oNic.attachmentType == vboxcon.NetworkAttachmentType_Generic:
1913 reporter.log(" attachmentType: Generic (%s)" % (oNic.attachmentType));
1914 reporter.log(" generic-driver: %s" % (oNic.GenericDriver));
1915 else:
1916 reporter.log(" attachmentType: unknown-%s" % (oNic.attachmentType));
1917 else:
1918 reporter.log(" attachmentType: unknown-%s" % (oNic.attachmentType));
1919 if oNic.traceEnabled:
1920 reporter.log(" traceFile: %s" % (oNic.traceFile));
1921 self.processPendingEvents();
1922 return True;
1923
1924 def logVmInfo(self, oVM): # pylint: disable=R0915,R0912
1925 """
1926 Logs VM configuration details.
1927
1928 This is copy, past, search, replace and edit of infoCmd from vboxshell.py.
1929 """
1930 try:
1931 fRc = self._logVmInfoUnsafe(oVM);
1932 except:
1933 reporter.logXcpt();
1934 fRc = False;
1935 return fRc;
1936
1937 def logVmInfoByName(self, sName):
1938 """
1939 logVmInfo + getVmByName.
1940 """
1941 return self.logVmInfo(self.getVmByName(sName));
1942
1943 def tryFindGuestOsId(self, sIdOrDesc):
1944 """
1945 Takes a guest OS ID or Description and returns the ID.
1946 If nothing matching it is found, the input is returned unmodified.
1947 """
1948
1949 if self.fpApiVer >= 4.0:
1950 if sIdOrDesc == 'Solaris (64 bit)':
1951 sIdOrDesc = 'Oracle Solaris 10 5/09 and earlier (64 bit)';
1952
1953 try:
1954 aoGuestTypes = self.oVBoxMgr.getArray(self.oVBox, 'GuestOSTypes');
1955 except:
1956 reporter.logXcpt();
1957 else:
1958 for oGuestOS in aoGuestTypes:
1959 try:
1960 sId = oGuestOS.id;
1961 sDesc = oGuestOS.description;
1962 except:
1963 reporter.logXcpt();
1964 else:
1965 if sIdOrDesc == sId or sIdOrDesc == sDesc:
1966 sIdOrDesc = sId;
1967 break;
1968 self.processPendingEvents();
1969 return sIdOrDesc
1970
1971 def resourceFindVmHd(self, sVmName, sFlavor):
1972 """
1973 Search the test resources for the most recent VM HD.
1974
1975 Returns path relative to the test resource root.
1976 """
1977 ## @todo implement a proper search algo here.
1978 return '4.2/' + sFlavor + '/' + sVmName + '/t-' + sVmName + '.vdi';
1979
1980
1981 #
1982 # VM Api wrappers that logs errors, hides exceptions and other details.
1983 #
1984
1985 # pylint: disable=R0913,R0914
1986 def createTestVM(self, sName, iGroup, sHd = None, cMbRam = None, cCpus = 1, fVirtEx = None, fNestedPaging = None, \
1987 sDvdImage = None, sKind = "Other", fIoApic = None, fPae = None, fFastBootLogo = True, \
1988 eNic0Type = None, eNic0AttachType = None, sNic0NetName = 'default', sNic0MacAddr = 'grouped', \
1989 sFloppy = None, fNatForwardingForTxs = None, sHddControllerType = 'IDE Controller', \
1990 fVmmDevTestingPart = None, fVmmDevTestingMmio = False):
1991 """
1992 Creates a test VM with a immutable HD from the test resources.
1993 """
1994 if not self.importVBoxApi():
1995 return None;
1996
1997 # create + register the VM
1998 try:
1999 if self.fpApiVer >= 4.2: # Introduces grouping (third parameter, empty for now).
2000 oVM = self.oVBox.createMachine("", sName, [], self.tryFindGuestOsId(sKind), "");
2001 elif self.fpApiVer >= 4.0:
2002 oVM = self.oVBox.createMachine("", sName, self.tryFindGuestOsId(sKind), "", False);
2003 elif self.fpApiVer >= 3.2:
2004 oVM = self.oVBox.createMachine(sName, self.tryFindGuestOsId(sKind), "", "", False);
2005 else:
2006 oVM = self.oVBox.createMachine(sName, self.tryFindGuestOsId(sKind), "", "");
2007 try:
2008 oVM.saveSettings();
2009 try:
2010 self.oVBox.registerMachine(oVM);
2011 except:
2012 raise;
2013 except:
2014 if self.fpApiVer >= 4.0:
2015 try:
2016 if self.fpApiVer >= 4.3:
2017 oProgress = oVM.deleteConfig(None);
2018 else:
2019 oProgress = oVM.delete(None);
2020 self.waitOnProgress(oProgress);
2021 except:
2022 reporter.logXcpt();
2023 else:
2024 try: oVM.deleteSettings();
2025 except: reporter.logXcpt();
2026 raise;
2027 except:
2028 reporter.errorXcpt('failed to create vm "%s"' % (sName));
2029 return None;
2030
2031 # Configure the VM.
2032 fRc = True;
2033 oSession = self.openSession(oVM);
2034 if oSession is not None:
2035 fRc = oSession.setupPreferredConfig();
2036
2037 if fRc and cMbRam is not None :
2038 fRc = oSession.setRamSize(cMbRam);
2039 if fRc and cCpus is not None:
2040 fRc = oSession.setCpuCount(cCpus);
2041 if fRc and fVirtEx is not None:
2042 fRc = oSession.enableVirtEx(fVirtEx);
2043 if fRc and fNestedPaging is not None:
2044 fRc = oSession.enableNestedPaging(fNestedPaging);
2045 if fRc and fIoApic is not None:
2046 fRc = oSession.enableIoApic(fIoApic);
2047 if fRc and fPae is not None:
2048 fRc = oSession.enablePae(fPae);
2049 if fRc and sDvdImage is not None:
2050 fRc = oSession.attachDvd(sDvdImage);
2051 if fRc and sHd is not None:
2052 fRc = oSession.attachHd(sHd, sHddControllerType);
2053 if fRc and sFloppy is not None:
2054 fRc = oSession.attachFloppy(sFloppy);
2055 if fRc and eNic0Type is not None:
2056 fRc = oSession.setNicType(eNic0Type, 0);
2057 if fRc and (eNic0AttachType is not None or (sNic0NetName is not None and sNic0NetName != 'default')):
2058 fRc = oSession.setNicAttachment(eNic0AttachType, sNic0NetName, 0);
2059 if fRc and sNic0MacAddr is not None:
2060 if sNic0MacAddr == 'grouped':
2061 sNic0MacAddr = '%02u' % (iGroup);
2062 fRc = oSession.setNicMacAddress(sNic0MacAddr, 0);
2063 if fRc and fNatForwardingForTxs is True:
2064 fRc = oSession.setupNatForwardingForTxs();
2065 if fRc and fFastBootLogo is not None:
2066 fRc = oSession.setupBootLogo(fFastBootLogo);
2067 if fRc and self.fEnableVrdp:
2068 fRc = oSession.setupVrdp(True, self.uVrdpBasePort + iGroup);
2069 if fRc and fVmmDevTestingPart is not None:
2070 fRc = oSession.enableVmmDevTestingPart(fVmmDevTestingPart, fVmmDevTestingMmio);
2071
2072 if fRc: fRc = oSession.saveSettings();
2073 if not fRc: oSession.discardSettings(True);
2074 oSession.close();
2075 if not fRc:
2076 try: self.oVBox.unregisterMachine(oVM.id);
2077 except: pass;
2078 if self.fpApiVer >= 4.0:
2079 try:
2080 if self.fpApiVer >= 4.3:
2081 oProgress = oVM.deleteConfig(None);
2082 else:
2083 oProgress = oVM.delete(None);
2084 self.waitOnProgress(oProgress);
2085 except:
2086 reporter.logXcpt();
2087 else:
2088 try: oVM.deleteSettings();
2089 except: reporter.logXcpt();
2090 return None;
2091
2092 # success.
2093 reporter.log('created "%s" with name "%s"' % (oVM.id, sName));
2094 self.aoVMs.append(oVM);
2095 self.logVmInfo(oVM); # testing...
2096 return oVM;
2097 # pylint: enable=R0913,R0914
2098
2099 def addTestMachine(self, sNameOrId, fQuiet = False):
2100 """
2101 Adds an already existing (that is, configured) test VM to the
2102 test VM list.
2103 """
2104 # find + add the VM to the list.
2105 try:
2106 if self.fpApiVer >= 4.0:
2107 oVM = self.oVBox.findMachine(sNameOrId);
2108 else:
2109 reporter.error('Port me!'); ## @todo Add support for older version < 4.0.
2110 except:
2111 reporter.errorXcpt('could not find vm "%s"' % (sNameOrId,));
2112 return None;
2113
2114 self.aoVMs.append(oVM);
2115 if not fQuiet:
2116 reporter.log('Added "%s" with name "%s"' % (oVM.id, sNameOrId));
2117 self.logVmInfo(oVM);
2118 return oVM;
2119
2120 def openSession(self, oVM):
2121 """
2122 Opens a session for the VM. Returns the a Session wrapper object that
2123 will automatically close the session when the wrapper goes out of scope.
2124
2125 On failure None is returned and an error is logged.
2126 """
2127 try:
2128 sUuid = oVM.id;
2129 except:
2130 reporter.errorXcpt('failed to get the UUID for VM "%s"' % (oVM,));
2131 return None;
2132
2133 # This loop is a kludge to deal with us racing the closing of the
2134 # direct session of a previous VM run. See waitOnDirectSessionClose.
2135 for i in range(10):
2136 try:
2137 if self.fpApiVer <= 3.2:
2138 oSession = self.oVBoxMgr.openMachineSession(sUuid);
2139 else:
2140 oSession = self.oVBoxMgr.openMachineSession(oVM);
2141 break;
2142 except:
2143 if i == 9:
2144 reporter.errorXcpt('failed to open session for "%s" ("%s")' % (sUuid, oVM));
2145 return None;
2146 if i > 0:
2147 reporter.logXcpt('warning: failed to open session for "%s" ("%s") - retrying in %u secs' % (sUuid, oVM, i));
2148 self.waitOnDirectSessionClose(oVM, 5000 + i * 1000);
2149 from testdriver.vboxwrappers import SessionWrapper;
2150 return SessionWrapper(oSession, oVM, self.oVBox, self.oVBoxMgr, self, False);
2151
2152 def getVmByName(self, sName):
2153 """
2154 Get a test VM by name. Returns None if not found, logged.
2155 """
2156 # Look it up in our 'cache'.
2157 for oVM in self.aoVMs:
2158 try:
2159 #reporter.log2('cur: %s / %s (oVM=%s)' % (oVM.name, oVM.id, oVM));
2160 if oVM.name == sName:
2161 return oVM;
2162 except:
2163 reporter.errorXcpt('failed to get the name from the VM "%s"' % (oVM));
2164
2165 # Look it up the standard way.
2166 return self.addTestMachine(sName, fQuiet = True);
2167
2168 def getVmByUuid(self, sUuid):
2169 """
2170 Get a test VM by uuid. Returns None if not found, logged.
2171 """
2172 # Look it up in our 'cache'.
2173 for oVM in self.aoVMs:
2174 try:
2175 if oVM.id == sUuid:
2176 return oVM;
2177 except:
2178 reporter.errorXcpt('failed to get the UUID from the VM "%s"' % (oVM));
2179
2180 # Look it up the standard way.
2181 return self.addTestMachine(sUuid, fQuiet = True);
2182
2183 def waitOnProgress(self, oProgress, cMsTimeout = 1000000, fErrorOnTimeout = True, cMsInterval = 1000):
2184 """
2185 Waits for a progress object to complete. Returns the status code.
2186 """
2187 # Wait for progress no longer than cMsTimeout time period.
2188 tsStart = datetime.datetime.now()
2189 while True:
2190 self.processPendingEvents();
2191 try:
2192 if oProgress.completed:
2193 break;
2194 except:
2195 return -1;
2196 self.processPendingEvents();
2197
2198 tsNow = datetime.datetime.now()
2199 tsDelta = tsNow - tsStart
2200 if ((tsDelta.microseconds + tsDelta.seconds * 1000000) / 1000) > cMsTimeout:
2201 if fErrorOnTimeout:
2202 reporter.errorTimeout('Timeout while waiting for progress.')
2203 return -1
2204
2205 try: oProgress.waitForCompletion(cMsInterval);
2206 except: return -2;
2207
2208 try: rc = oProgress.resultCode;
2209 except: rc = -2;
2210 self.processPendingEvents();
2211 return rc;
2212
2213 def waitOnDirectSessionClose(self, oVM, cMsTimeout):
2214 """
2215 Waits for the VM process to close it's current direct session.
2216
2217 Returns None.
2218 """
2219 # Get the original values so we're not subject to
2220 try:
2221 eCurState = oVM.sessionState;
2222 sCurType = sOrgType = oVM.sessionType;
2223 if self.fpApiVer >= 4.2:
2224 iCurPid = iOrgPid = oVM.sessionPID;
2225 else:
2226 iCurPid = iOrgPid = oVM.sessionPid;
2227 except Exception, oXcpt:
2228 if ComError.notEqual(oXcpt, ComError.E_ACCESSDENIED):
2229 reporter.logXcpt();
2230 self.processPendingEvents();
2231 return None;
2232 self.processPendingEvents();
2233
2234 msStart = base.timestampMilli();
2235 while iCurPid == iOrgPid \
2236 and sCurType == sOrgType \
2237 and sCurType != '' \
2238 and base.timestampMilli() - msStart < cMsTimeout \
2239 and ( eCurState == vboxcon.SessionState_Unlocking \
2240 or eCurState == vboxcon.SessionState_Spawning \
2241 or eCurState == vboxcon.SessionState_Locked):
2242 self.processEvents(1000);
2243 try:
2244 eCurState = oVM.sessionState;
2245 sCurType = oVM.sessionType;
2246 iCurPid = oVM.sessionPID if self.fpApiVer >= 4.2 else oVM.sessionPid;
2247 except Exception, oXcpt:
2248 if ComError.notEqual(oXcpt, ComError.E_ACCESSDENIED):
2249 reporter.logXcpt();
2250 break;
2251 self.processPendingEvents();
2252 self.processPendingEvents();
2253 return None;
2254
2255 def uploadStartupLogFile(self, oVM, sVmName):
2256 """
2257 Uploads the VBoxStartup.log when present.
2258 """
2259 fRc = True;
2260 try:
2261 sLogFile = os.path.join(oVM.logFolder, 'VBoxStartup.log');
2262 except:
2263 reporter.logXcpt();
2264 fRc = False;
2265 else:
2266 if os.path.isfile(sLogFile):
2267 reporter.addLogFile(sLogFile, 'log/release/vm', '%s startup log' % (sVmName, ),
2268 sAltName = '%s-%s' % (sVmName, os.path.basename(sLogFile),));
2269 return fRc;
2270
2271 def startVmEx(self, oVM, fWait = True, sType = None, sName = None, asEnv = None): # pylint: disable=R0914,R0915
2272 """
2273 Start the VM, returning the VM session and progress object on success.
2274 The session is also added to the task list and to the aoRemoteSessions set.
2275
2276 asEnv is a list of string on the putenv() form.
2277
2278 On failure (None, None) is returned and an error is logged.
2279 """
2280 # Massage and check the input.
2281 if sType is None:
2282 sType = self.sSessionType;
2283 if sName is None:
2284 try: sName = oVM.name;
2285 except: sName = 'bad-vm-handle';
2286 reporter.log2('startVmEx: sName=%s fWait=%s sType=%s' % (sName, fWait, sType));
2287 if oVM is None:
2288 return (None, None);
2289
2290 ## @todo Do this elsewhere.
2291 # Hack alert. Disables all annoying GUI popups.
2292 if sType == 'gui' and len(self.aoRemoteSessions) == 0:
2293 try:
2294 self.oVBox.setExtraData('GUI/Input/AutoCapture', 'false');
2295 if self.fpApiVer >= 3.2:
2296 self.oVBox.setExtraData('GUI/LicenseAgreed', '8');
2297 else:
2298 self.oVBox.setExtraData('GUI/LicenseAgreed', '7');
2299 self.oVBox.setExtraData('GUI/RegistrationData', 'triesLeft=0');
2300 self.oVBox.setExtraData('GUI/SUNOnlineData', 'triesLeft=0');
2301 self.oVBox.setExtraData('GUI/SuppressMessages', 'confirmVMReset,remindAboutMouseIntegrationOn,'
2302 'remindAboutMouseIntegrationOff,remindAboutPausedVMInput,confirmInputCapture,'
2303 'confirmGoingFullscreen,remindAboutInaccessibleMedia,remindAboutWrongColorDepth,'
2304 'confirmRemoveMedium,allPopupPanes,allMessageBoxes,all');
2305 self.oVBox.setExtraData('GUI/UpdateDate', 'never');
2306 self.oVBox.setExtraData('GUI/PreventBetaWarning', self.oVBox.version);
2307 except:
2308 reporter.logXcpt();
2309
2310 # The UUID for the name.
2311 try:
2312 sUuid = oVM.id;
2313 except:
2314 reporter.errorXcpt('failed to get the UUID for VM "%s"' % (oVM));
2315 return (None, None);
2316 self.processPendingEvents();
2317
2318 # Construct the environment.
2319 sLogFile = '%s/VM-%s.log' % (self.sScratchPath, sUuid);
2320 try: os.remove(sLogFile);
2321 except: pass;
2322 if self.sLogSessionDest:
2323 sLogDest = self.sLogSessionDest;
2324 else:
2325 sLogDest = 'file=%s' % sLogFile;
2326 sEnv = 'VBOX_LOG=%s\nVBOX_LOG_FLAGS=%s\nVBOX_LOG_DEST=%s\nVBOX_RELEASE_LOG_FLAGS=append time' \
2327 % (self.sLogSessionGroups, self.sLogSessionFlags, sLogDest,);
2328 if sType == 'gui':
2329 sEnv += '\nVBOX_GUI_DBG_ENABLED=1'
2330 if asEnv is not None and len(asEnv) > 0:
2331 sEnv += '\n' + ('\n'.join(asEnv));
2332
2333 # Shortcuts for local testing.
2334 oProgress = oWrapped = None;
2335 oTestVM = self.oTestVmSet.findTestVmByName(sName) if self.oTestVmSet is not None else None;
2336 try:
2337 if oTestVM is not None \
2338 and oTestVM.fSnapshotRestoreCurrent is True:
2339 if oVM.state is vboxcon.MachineState_Running:
2340 reporter.log2('Machine "%s" already running.' % (sName,));
2341 oProgress = None;
2342 oWrapped = self.openSession(oVM);
2343 else:
2344 reporter.log2('Checking if snapshot for machine "%s" exists.' % (sName,));
2345 oSessionWrapperRestore = self.openSession(oVM);
2346 if oSessionWrapperRestore is not None:
2347 oSnapshotCur = oVM.currentSnapshot;
2348 if oSnapshotCur is not None:
2349 reporter.log2('Restoring snapshot for machine "%s".' % (sName,));
2350 oSessionWrapperRestore.restoreSnapshot(oSnapshotCur);
2351 reporter.log2('Current snapshot for machine "%s" restored.' % (sName,));
2352 else:
2353 reporter.log('warning: no current snapshot for machine "%s" found.' % (sName,));
2354 oSessionWrapperRestore.close();
2355 except:
2356 reporter.errorXcpt();
2357 return (None, None);
2358
2359 # Open a remote session, wait for this operation to complete.
2360 # (The loop is a kludge to deal with us racing the closing of the
2361 # direct session of a previous VM run. See waitOnDirectSessionClose.)
2362 if oWrapped is None:
2363 for i in range(10):
2364 try:
2365 if self.fpApiVer < 4.3 \
2366 or (self.fpApiVer == 4.3 and not hasattr(self.oVBoxMgr, 'getSessionObject')):
2367 oSession = self.oVBoxMgr.mgr.getSessionObject(self.oVBox); # pylint: disable=E1101
2368 else:
2369 oSession = self.oVBoxMgr.getSessionObject(self.oVBox); # pylint: disable=E1101
2370 if self.fpApiVer < 3.3:
2371 oProgress = self.oVBox.openRemoteSession(oSession, sUuid, sType, sEnv);
2372 else:
2373 oProgress = oVM.launchVMProcess(oSession, sType, sEnv);
2374 break;
2375 except:
2376 if i == 9:
2377 reporter.errorXcpt('failed to start VM "%s" ("%s"), aborting.' % (sUuid, sName));
2378 return (None, None);
2379 oSession = None;
2380 if i >= 0:
2381 reporter.logXcpt('warning: failed to start VM "%s" ("%s") - retrying in %u secs.' % (sUuid, oVM, i)); # pylint: disable=C0301
2382 self.waitOnDirectSessionClose(oVM, 5000 + i * 1000);
2383 if fWait and oProgress is not None:
2384 rc = self.waitOnProgress(oProgress);
2385 if rc < 0:
2386 self.waitOnDirectSessionClose(oVM, 5000);
2387 try:
2388 if oSession is not None:
2389 oSession.close();
2390 except: pass;
2391 reportError(oProgress, 'failed to open session for "%s"' % (sName));
2392 self.uploadStartupLogFile(oVM, sName);
2393 return (None, None);
2394 reporter.log2('waitOnProgress -> %s' % (rc,));
2395
2396 # Wrap up the session object and push on to the list before returning it.
2397 if oWrapped is None:
2398 from testdriver.vboxwrappers import SessionWrapper;
2399 oWrapped = SessionWrapper(oSession, oVM, self.oVBox, self.oVBoxMgr, self, True, sName, sLogFile);
2400
2401 oWrapped.registerEventHandlerForTask();
2402 self.aoRemoteSessions.append(oWrapped);
2403 if oWrapped is not self.aoRemoteSessions[len(self.aoRemoteSessions) - 1]:
2404 reporter.error('not by reference: oWrapped=%s aoRemoteSessions[%s]=%s'
2405 % (oWrapped, len(self.aoRemoteSessions) - 1,
2406 self.aoRemoteSessions[len(self.aoRemoteSessions) - 1]));
2407 self.addTask(oWrapped);
2408
2409 reporter.log2('startVmEx: oSession=%s, oSessionWrapper=%s, oProgress=%s' % (oSession, oWrapped, oProgress));
2410
2411 from testdriver.vboxwrappers import ProgressWrapper;
2412 return (oWrapped, ProgressWrapper(oProgress, self.oVBoxMgr, self,
2413 'starting %s' % (sName,)) if oProgress else None);
2414
2415 def startVm(self, oVM, sType=None, sName = None, asEnv = None):
2416 """ Simplified version of startVmEx. """
2417 oSession, _ = self.startVmEx(oVM, True, sType, sName, asEnv = asEnv);
2418 return oSession;
2419
2420 def startVmByNameEx(self, sName, fWait=True, sType=None, asEnv = None):
2421 """
2422 Start the VM, returning the VM session and progress object on success.
2423 The session is also added to the task list and to the aoRemoteSessions set.
2424
2425 On failure (None, None) is returned and an error is logged.
2426 """
2427 oVM = self.getVmByName(sName);
2428 if oVM is None:
2429 return (None, None);
2430 return self.startVmEx(oVM, fWait, sType, sName, asEnv = asEnv);
2431
2432 def startVmByName(self, sName, sType=None, asEnv = None):
2433 """
2434 Start the VM, returning the VM session on success. The session is
2435 also added to the task list and to the aoRemoteSessions set.
2436
2437 On failure None is returned and an error is logged.
2438 """
2439 oSession, _ = self.startVmByNameEx(sName, True, sType, asEnv = asEnv);
2440 return oSession;
2441
2442 def terminateVmBySession(self, oSession, oProgress = None, fTakeScreenshot = None):
2443 """
2444 Terminates the VM specified by oSession and adds the release logs to
2445 the test report.
2446
2447 This will try archive this by using powerOff, but will resort to
2448 tougher methods if that fails.
2449
2450 The session will always be removed from the task list.
2451 The session will be closed unless we fail to kill the process.
2452 The session will be removed from the remote session list if closed.
2453
2454 The progress object (a wrapper!) is for teleportation and similar VM
2455 operations, it will be attempted canceled before powering off the VM.
2456 Failures are logged but ignored.
2457 The progress object will always be removed from the task list.
2458
2459 Returns True if powerOff and session close both succeed.
2460 Returns False if on failure (logged), including when we successfully
2461 kill the VM process.
2462 """
2463 reporter.log2('terminateVmBySession: oSession=%s (pid=%s) oProgress=%s' % (oSession.sName, oSession.getPid(), oProgress));
2464
2465 # Call getPid first to make sure the PID is cached in the wrapper.
2466 oSession.getPid();
2467
2468 #
2469 # Take Screenshot and upload it (see below) to Test Manager if appropriate/requested.
2470 #
2471 sLastScreenshotPath = None
2472 if fTakeScreenshot is True or self.fAlwaysUploadScreenshots or reporter.testErrorCount() > 0:
2473 sLastScreenshotPath = os.path.join(self.sScratchPath, "LastScreenshot-%s.png" % oSession.sName)
2474 fRc = oSession.takeScreenshot(sLastScreenshotPath)
2475 if fRc is not True:
2476 sLastScreenshotPath = None
2477
2478 #
2479 # Terminate the VM
2480 #
2481
2482 # Cancel the progress object if specified.
2483 if oProgress is not None:
2484 if not oProgress.isCompleted() and oProgress.isCancelable():
2485 reporter.log2('terminateVmBySession: canceling "%s"...' % (oProgress.sName));
2486 try:
2487 oProgress.o.cancel();
2488 except:
2489 reporter.logXcpt();
2490 else:
2491 oProgress.wait();
2492 self.removeTask(oProgress);
2493
2494 # Check if the VM has terminated by it self before powering it off.
2495 fClose = True;
2496 fRc = oSession.pollTask();
2497 if fRc is not True:
2498 reporter.log('terminateVmBySession: powering off "%s"...' % (oSession.sName,));
2499 fRc = oSession.powerOff(fFudgeOnFailure = False);
2500 if fRc is not True:
2501 # power off failed, try terminate it in a nice manner.
2502 fRc = False;
2503 uPid = oSession.getPid();
2504 if uPid is not None:
2505 reporter.error('terminateVmBySession: Terminating PID %u (VM %s)' % (uPid, oSession.sName));
2506 fClose = base.processTerminate(uPid);
2507 if fClose is True:
2508 self.waitOnDirectSessionClose(oSession.oVM, 5000);
2509 fClose = oSession.waitForTask(1000);
2510
2511 if fClose is not True:
2512 # Being nice failed...
2513 reporter.error('terminateVmBySession: Termination failed, trying to kill PID %u (VM %s) instead' \
2514 % (uPid, oSession.sName));
2515 fClose = base.processKill(uPid);
2516 if fClose is True:
2517 self.waitOnDirectSessionClose(oSession.oVM, 5000);
2518 fClose = oSession.waitForTask(1000);
2519 if fClose is not True:
2520 reporter.error('terminateVmBySession: Failed to kill PID %u (VM %s)' % (uPid, oSession.sName));
2521
2522 # The final steps.
2523 if fClose is True:
2524 oSession.close();
2525 self.waitOnDirectSessionClose(oSession.oVM, 10000);
2526 try:
2527 eState = oSession.oVM.state;
2528 except:
2529 reporter.logXcpt();
2530 else:
2531 if eState == vboxcon.MachineState_Aborted:
2532 reporter.error('terminateVmBySession: The VM "%s" aborted!' % (oSession.sName,));
2533 self.removeTask(oSession);
2534
2535 #
2536 # Add the release log, debug log and a screenshot of the VM to the test report.
2537 #
2538 if self.fAlwaysUploadLogs or reporter.testErrorCount() > 0:
2539 oSession.addLogsToReport();
2540
2541 # Add a screenshot if it has been requested and taken successfully.
2542 if sLastScreenshotPath is not None:
2543 if reporter.testErrorCount() > 0:
2544 reporter.addLogFile(sLastScreenshotPath, 'screenshot/failure', 'Last VM screenshot');
2545 else:
2546 reporter.addLogFile(sLastScreenshotPath, 'screenshot/success', 'Last VM screenshot');
2547
2548 return fRc;
2549
2550
2551 #
2552 # Some information query functions (mix).
2553 #
2554 # Methods require the VBox API. If the information is provided by both
2555 # the testboxscript as well as VBox API, we'll check if it matches.
2556 #
2557
2558 def _hasHostCpuFeature(self, sEnvVar, sEnum, fpApiMinVer, fQuiet):
2559 """
2560 Common Worker for hasHostNestedPaging() and hasHostHwVirt().
2561
2562 Returns True / False.
2563 Raises exception on environment / host mismatch.
2564 """
2565 fEnv = os.environ.get(sEnvVar, None);
2566 if fEnv is not None:
2567 fEnv = fEnv.lower() not in [ 'false', 'f', 'not', 'no', 'n', '0', ];
2568
2569 fVBox = None;
2570 self.importVBoxApi();
2571 if self.fpApiVer >= fpApiMinVer and hasattr(vboxcon, sEnum):
2572 try:
2573 fVBox = self.oVBox.host.getProcessorFeature(getattr(vboxcon, sEnum));
2574 except:
2575 if not fQuiet:
2576 reporter.logXcpt();
2577
2578 if fVBox is not None:
2579 if fEnv is not None:
2580 assert fVBox == fEnv, 'Misconfigured TestBox: fVBox=%s (%s) vs. fEnv=%s (%s)' % (fVBox, sEnum, fEnv, sEnvVar);
2581 return fVBox;
2582 if fEnv is not None:
2583 return fEnv;
2584 return False;
2585
2586 def hasHostHwVirt(self, fQuiet = False):
2587 """
2588 Checks if hardware assisted virtualization is supported by the host.
2589
2590 Returns True / False.
2591 Raises exception on environment / host mismatch.
2592 """
2593 return self._hasHostCpuFeature('TESTBOX_HAS_HW_VIRT', 'ProcessorFeature_HWVirtEx', 3.1, fQuiet);
2594
2595 def hasHostNestedPaging(self, fQuiet = False):
2596 """
2597 Checks if nested paging is supported by the host.
2598
2599 Returns True / False.
2600 Raises exception on environment / host mismatch.
2601 """
2602 return self._hasHostCpuFeature('TESTBOX_HAS_NESTED_PAGING', 'ProcessorFeature_NestedPaging', 4.2, fQuiet) \
2603 and self.hasHostHwVirt(fQuiet);
2604
2605 def hasHostLongMode(self, fQuiet = False):
2606 """
2607 Checks if the host supports 64-bit guests.
2608
2609 Returns True / False.
2610 Raises exception on environment / host mismatch.
2611 """
2612 # Note that the testboxscript doesn't export this variable atm.
2613 return self._hasHostCpuFeature('TESTBOX_HAS_LONG_MODE', 'ProcessorFeature_LongMode', 3.1, fQuiet);
2614
2615 def getHostCpuCount(self, fQuiet = False):
2616 """
2617 Returns the number of CPUs on the host.
2618
2619 Returns True / False.
2620 Raises exception on environment / host mismatch.
2621 """
2622 cEnv = os.environ.get('TESTBOX_CPU_COUNT', None);
2623 if cEnv is not None:
2624 cEnv = int(cEnv);
2625
2626 try:
2627 cVBox = self.oVBox.host.processorOnlineCount;
2628 except:
2629 if not fQuiet:
2630 reporter.logXcpt();
2631 cVBox = None;
2632
2633 if cVBox is not None:
2634 if cEnv is not None:
2635 assert cVBox == cEnv, 'Misconfigured TestBox: VBox: %u CPUs, testboxscript: %u CPUs' % (cVBox, cEnv);
2636 return cVBox;
2637 if cEnv is not None:
2638 return cEnv;
2639 return 1;
2640
2641 def _getHostCpuDesc(self, fQuiet = False):
2642 """
2643 Internal method used for getting the host CPU description from VBoxSVC.
2644 Returns description string, on failure an empty string is returned.
2645 """
2646 try:
2647 return self.oVBox.host.getProcessorDescription(0);
2648 except:
2649 if not fQuiet:
2650 reporter.logXcpt();
2651 return '';
2652
2653 def isHostCpuAmd(self, fQuiet = False):
2654 """
2655 Checks if the host CPU vendor is AMD.
2656
2657 Returns True / False.
2658 """
2659 sCpuDesc = self._getHostCpuDesc(fQuiet);
2660 return sCpuDesc.startswith("AMD") or sCpuDesc == 'AuthenticAMD';
2661
2662 def isHostCpuIntel(self, fQuiet = False):
2663 """
2664 Checks if the host CPU vendor is Intel.
2665
2666 Returns True / False.
2667 """
2668 sCpuDesc = self._getHostCpuDesc(fQuiet);
2669 return sCpuDesc.startswith("Intel") or sCpuDesc == 'GenuineIntel';
2670
2671 def isHostCpuVia(self, fQuiet = False):
2672 """
2673 Checks if the host CPU vendor is VIA (or Centaur).
2674
2675 Returns True / False.
2676 """
2677 sCpuDesc = self._getHostCpuDesc(fQuiet);
2678 return sCpuDesc.startswith("VIA") or sCpuDesc == 'CentaurHauls';
2679
2680
2681 #
2682 # Testdriver execution methods.
2683 #
2684
2685 def handleTask(self, oTask, sMethod):
2686 """
2687 Callback method for handling unknown tasks in the various run loops.
2688
2689 The testdriver should override this if it already tasks running when
2690 calling startVmAndConnectToTxsViaTcp, txsRunTest or similar methods.
2691 Call super to handle unknown tasks.
2692
2693 Returns True if handled, False if not.
2694 """
2695 reporter.error('%s: unknown task %s' % (sMethod, oTask));
2696 return False;
2697
2698 def txsDoTask(self, oSession, oTxsSession, fnAsync, aArgs):
2699 """
2700 Generic TXS task wrapper which waits both on the TXS and the session tasks.
2701
2702 Returns False on error, logged.
2703
2704 Returns task result on success.
2705 """
2706 # All async methods ends with the following to args.
2707 cMsTimeout = aArgs[-2];
2708 fIgnoreErrors = aArgs[-1];
2709
2710 fRemoveVm = self.addTask(oSession);
2711 fRemoveTxs = self.addTask(oTxsSession);
2712
2713 rc = fnAsync(*aArgs); # pylint: disable=W0142
2714 if rc is True:
2715 rc = False;
2716 oTask = self.waitForTasks(cMsTimeout + 1);
2717 if oTask is oTxsSession:
2718 if oTxsSession.isSuccess():
2719 rc = oTxsSession.getResult();
2720 elif fIgnoreErrors is True:
2721 reporter.log( 'txsDoTask: task failed (%s)' % (oTxsSession.getLastReply()[1],));
2722 else:
2723 reporter.error('txsDoTask: task failed (%s)' % (oTxsSession.getLastReply()[1],));
2724 else:
2725 oTxsSession.cancelTask();
2726 if oTask is None:
2727 if fIgnoreErrors is True:
2728 reporter.log( 'txsDoTask: The task timed out.');
2729 else:
2730 reporter.errorTimeout('txsDoTask: The task timed out.');
2731 elif oTask is oSession:
2732 reporter.error('txsDoTask: The VM terminated unexpectedly');
2733 else:
2734 if fIgnoreErrors is True:
2735 reporter.log( 'txsDoTask: An unknown task %s was returned' % (oTask,));
2736 else:
2737 reporter.error('txsDoTask: An unknown task %s was returned' % (oTask,));
2738 else:
2739 reporter.error('txsDoTask: fnAsync returned %s' % (rc,));
2740
2741 if fRemoveTxs:
2742 self.removeTask(oTxsSession);
2743 if fRemoveVm:
2744 self.removeTask(oSession);
2745 return rc;
2746
2747 # pylint: disable=C0111
2748
2749 def txsDisconnect(self, oSession, oTxsSession, cMsTimeout = 30000, fIgnoreErrors = False):
2750 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncDisconnect,
2751 (self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2752
2753 def txsUuid(self, oSession, oTxsSession, cMsTimeout = 30000, fIgnoreErrors = False):
2754 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncUuid,
2755 (self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2756
2757 def txsMkDir(self, oSession, oTxsSession, sRemoteDir, fMode = 0700, cMsTimeout = 30000, fIgnoreErrors = False):
2758 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncMkDir,
2759 (sRemoteDir, fMode, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2760
2761 def txsMkDirPath(self, oSession, oTxsSession, sRemoteDir, fMode = 0700, cMsTimeout = 30000, fIgnoreErrors = False):
2762 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncMkDirPath,
2763 (sRemoteDir, fMode, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2764
2765 def txsMkSymlink(self, oSession, oTxsSession, sLinkTarget, sLink, cMsTimeout = 30000, fIgnoreErrors = False):
2766 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncMkSymlink,
2767 (sLinkTarget, sLink, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2768
2769 def txsRmDir(self, oSession, oTxsSession, sRemoteDir, cMsTimeout = 30000, fIgnoreErrors = False):
2770 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncRmDir,
2771 (sRemoteDir, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2772
2773 def txsRmFile(self, oSession, oTxsSession, sRemoteFile, cMsTimeout = 30000, fIgnoreErrors = False):
2774 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncRmFile,
2775 (sRemoteFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2776
2777 def txsRmSymlink(self, oSession, oTxsSession, sRemoteSymlink, cMsTimeout = 30000, fIgnoreErrors = False):
2778 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncRmSymlink,
2779 (sRemoteSymlink, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2780
2781 def txsRmTree(self, oSession, oTxsSession, sRemoteTree, cMsTimeout = 30000, fIgnoreErrors = False):
2782 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncRmTree,
2783 (sRemoteTree, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2784
2785 def txsIsDir(self, oSession, oTxsSession, sRemoteDir, cMsTimeout = 30000, fIgnoreErrors = False):
2786 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncIsDir,
2787 (sRemoteDir, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2788
2789 def txsIsFile(self, oSession, oTxsSession, sRemoteFile, cMsTimeout = 30000, fIgnoreErrors = False):
2790 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncIsFile,
2791 (sRemoteFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2792
2793 def txsIsSymlink(self, oSession, oTxsSession, sRemoteSymlink, cMsTimeout = 30000, fIgnoreErrors = False):
2794 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncIsSymlink,
2795 (sRemoteSymlink, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2796
2797 def txsUploadFile(self, oSession, oTxsSession, sLocalFile, sRemoteFile, cMsTimeout = 30000, fIgnoreErrors = False):
2798 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncUploadFile, \
2799 (sLocalFile, sRemoteFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2800
2801 def txsUploadString(self, oSession, oTxsSession, sContent, sRemoteFile, cMsTimeout = 30000, fIgnoreErrors = False):
2802 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncUploadString, \
2803 (sContent, sRemoteFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2804
2805 def txsDownloadFile(self, oSession, oTxsSession, sRemoteFile, sLocalFile, cMsTimeout = 30000, fIgnoreErrors = False):
2806 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncDownloadFile, \
2807 (sRemoteFile, sLocalFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2808
2809 def txsDownloadFiles(self, oSession, oTxsSession, asFiles, fIgnoreErrors = False):
2810 """
2811 Convenience function to get files from the guest and stores it
2812 into the scratch directory for later (manual) review.
2813
2814 Returns True on success.
2815
2816 Returns False on failure, logged.
2817 """
2818 fRc = True;
2819 for sGstFile in asFiles:
2820 ## @todo Check for already existing files on the host and create a new
2821 # name for the current file to download.
2822 sTmpFile = os.path.join(self.sScratchPath, 'tmp-' + os.path.basename(sGstFile));
2823 reporter.log2('Downloading file "%s" to "%s" ...' % (sGstFile, sTmpFile));
2824 fRc = self.txsDownloadFile(oSession, oTxsSession, sGstFile, sTmpFile, 30 * 1000, fIgnoreErrors);
2825 try: os.unlink(sTmpFile);
2826 except: pass;
2827 if fRc:
2828 reporter.addLogFile(sTmpFile, 'misc/other', 'guest - ' + sGstFile);
2829 else:
2830 if fIgnoreErrors is not True:
2831 reporter.error('error downloading file "%s" to "%s"' % (sGstFile, sTmpFile));
2832 return fRc;
2833 reporter.log('warning: file "%s" was not downloaded, ignoring.' % (sGstFile,));
2834 return True;
2835
2836 def txsDownloadString(self, oSession, oTxsSession, sRemoteFile, cMsTimeout = 30000, fIgnoreErrors = False):
2837 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncDownloadString,
2838 (sRemoteFile, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2839
2840 def txsUnpackFile(self, oSession, oTxsSession, sRemoteFile, sRemoteDir, cMsTimeout = 30000, fIgnoreErrors = False):
2841 return self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncUnpackFile, \
2842 (sRemoteFile, sRemoteDir, self.adjustTimeoutMs(cMsTimeout), fIgnoreErrors));
2843
2844 # pylint: enable=C0111
2845
2846 def txsCdWait(self, oSession, oTxsSession, cMsTimeout = 30000, sFileCdWait = 'vboxtxs-readme.txt'):
2847 """
2848 Mostly an internal helper for txsRebootAndReconnectViaTcp and
2849 startVmAndConnectToTxsViaTcp that waits for the CDROM drive to become
2850 ready. It does this by polling for a file it knows to exist on the CD.
2851
2852 Returns True on success.
2853
2854 Returns False on failure, logged.
2855 """
2856
2857 fRemoveVm = self.addTask(oSession);
2858 fRemoveTxs = self.addTask(oTxsSession);
2859 cMsTimeout = self.adjustTimeoutMs(cMsTimeout);
2860 msStart = base.timestampMilli();
2861 cMsTimeout2 = cMsTimeout;
2862 fRc = oTxsSession.asyncIsFile('${CDROM}/%s' % (sFileCdWait), cMsTimeout2);
2863 if fRc is True:
2864 while True:
2865 # wait for it to complete.
2866 oTask = self.waitForTasks(cMsTimeout2 + 1);
2867 if oTask is not oTxsSession:
2868 oTxsSession.cancelTask();
2869 if oTask is None:
2870 reporter.errorTimeout('txsToCdWait: The task timed out (after %s ms).'
2871 % (base.timestampMilli() - msStart,));
2872 elif oTask is oSession:
2873 reporter.error('txsToCdWait: The VM terminated unexpectedly');
2874 else:
2875 reporter.error('txsToCdWait: An unknown task %s was returned' % (oTask,));
2876 fRc = False;
2877 break;
2878 if oTxsSession.isSuccess():
2879 break;
2880
2881 # Check for timeout.
2882 cMsElapsed = base.timestampMilli() - msStart;
2883 if cMsElapsed >= cMsTimeout:
2884 reporter.error('txsToCdWait: timed out');
2885 fRc = False;
2886 break;
2887
2888 # delay.
2889 self.sleep(1);
2890
2891 # resubmitt the task.
2892 cMsTimeout2 = msStart + cMsTimeout - base.timestampMilli();
2893 if cMsTimeout2 < 500:
2894 cMsTimeout2 = 500;
2895 fRc = oTxsSession.asyncIsFile('${CDROM}/%s' % (sFileCdWait), cMsTimeout2);
2896 if fRc is not True:
2897 reporter.error('txsToCdWait: asyncIsFile failed');
2898 break;
2899 else:
2900 reporter.error('txsToCdWait: asyncIsFile failed');
2901
2902 if fRemoveTxs:
2903 self.removeTask(oTxsSession);
2904 if fRemoveVm:
2905 self.removeTask(oSession);
2906 return fRc;
2907
2908 def txsDoConnectViaTcp(self, oSession, cMsTimeout, fNatForwardingForTxs = False):
2909 """
2910 Mostly an internal worker for connecting to TXS via TCP used by the
2911 *ViaTcp methods.
2912
2913 Returns a tuplet with True/False and TxsSession/None depending on the
2914 result. Errors are logged.
2915 """
2916
2917 reporter.log2('txsDoConnectViaTcp: oSession=%s, cMsTimeout=%s, fNatForwardingForTxs=%s'
2918 % (oSession, cMsTimeout, fNatForwardingForTxs));
2919
2920 cMsTimeout = self.adjustTimeoutMs(cMsTimeout);
2921 oTxsConnect = oSession.txsConnectViaTcp(cMsTimeout, fNatForwardingForTxs = fNatForwardingForTxs);
2922 if oTxsConnect is not None:
2923 self.addTask(oTxsConnect);
2924 fRemoveVm = self.addTask(oSession);
2925 oTask = self.waitForTasks(cMsTimeout + 1);
2926 reporter.log2('txsDoConnectViaTcp: waitForTasks returned %s' % (oTask,));
2927 self.removeTask(oTxsConnect);
2928 if oTask is oTxsConnect:
2929 oTxsSession = oTxsConnect.getResult();
2930 if oTxsSession is not None:
2931 reporter.log('txsDoConnectViaTcp: Connected to TXS on %s.' % (oTxsSession.oTransport.sHostname,));
2932 return (True, oTxsSession);
2933
2934 reporter.error('txsDoConnectViaTcp: failed to connect to TXS.');
2935 else:
2936 oTxsConnect.cancelTask();
2937 if oTask is None:
2938 reporter.errorTimeout('txsDoConnectViaTcp: connect stage 1 timed out');
2939 elif oTask is oSession:
2940 oSession.reportPrematureTermination('txsDoConnectViaTcp: ');
2941 else:
2942 reporter.error('txsDoConnectViaTcp: unknown/wrong task %s' % (oTask,));
2943 if fRemoveVm:
2944 self.removeTask(oSession);
2945 else:
2946 reporter.error('txsDoConnectViaTcp: txsConnectViaTcp failed');
2947 return (False, None);
2948
2949 def startVmAndConnectToTxsViaTcp(self, sVmName, fCdWait = False, cMsTimeout = 15*60000, \
2950 cMsCdWait = 30000, sFileCdWait = 'vboxtxs-readme.txt', \
2951 fNatForwardingForTxs = False):
2952 """
2953 Starts the specified VM and tries to connect to its TXS via TCP.
2954 The VM will be powered off if TXS doesn't respond before the specified
2955 time has elapsed.
2956
2957 Returns a the VM and TXS sessions (a two tuple) on success. The VM
2958 session is in the task list, the TXS session is not.
2959 Returns (None, None) on failure, fully logged.
2960 """
2961
2962 # Zap the guest IP to make sure we're not getting a stale entry
2963 # (unless we're restoring the VM of course).
2964 oTestVM = self.oTestVmSet.findTestVmByName(sVmName) if self.oTestVmSet is not None else None;
2965 if oTestVM is None \
2966 or oTestVM.fSnapshotRestoreCurrent is False:
2967 try:
2968 oSession1 = self.openSession(self.getVmByName(sVmName));
2969 oSession1.delGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
2970 oSession1.saveSettings(True);
2971 del oSession1;
2972 except:
2973 reporter.logXcpt();
2974
2975 # Start the VM.
2976 reporter.log('startVmAndConnectToTxsViaTcp: Starting(/preparing) "%s" (timeout %s s)...' % (sVmName, cMsTimeout / 1000));
2977 oSession = self.startVmByName(sVmName);
2978 if oSession is not None:
2979 # Connect to TXS.
2980 reporter.log2('startVmAndConnectToTxsViaTcp: Started(/prepared) "%s", connecting to TXS ...' % (sVmName,));
2981 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, cMsTimeout, fNatForwardingForTxs);
2982 if fRc is True:
2983 if fCdWait:
2984 # Wait for CD?
2985 fRc = self.txsCdWait(oSession, oTxsSession, cMsCdWait, sFileCdWait);
2986 if fRc is not True:
2987 reporter.error('startVmAndConnectToTxsViaTcp: txsCdWait failed');
2988 if fRc is True:
2989 # Success!
2990 return (oSession, oTxsSession);
2991 else:
2992 reporter.error('startVmAndConnectToTxsViaTcp: txsDoConnectViaTcp failed');
2993 # If something went wrong while waiting for TXS to be started - take VM screenshot before terminate it
2994 self.terminateVmBySession(oSession);
2995 return (None, None);
2996
2997 def txsRebootAndReconnectViaTcp(self, oSession, oTxsSession, fCdWait = False, cMsTimeout = 15*60000, \
2998 cMsCdWait = 30000, sFileCdWait = 'vboxtxs-readme.txt', fNatForwardingForTxs = False):
2999 """
3000 Executes the TXS reboot command
3001
3002 Returns A tuple of True and the new TXS session on success.
3003
3004 Returns A tuple of False and either the old TXS session or None on failure.
3005 """
3006 reporter.log2('txsRebootAndReconnect: cMsTimeout=%u' % (cMsTimeout,));
3007
3008 #
3009 # This stuff is a bit complicated because of rebooting being kind of
3010 # disruptive to the TXS and such... The protocol is that TXS will:
3011 # - ACK the reboot command.
3012 # - Shutdown the transport layer, implicitly disconnecting us.
3013 # - Execute the reboot operation.
3014 # - On failure, it will be re-init the transport layer and be
3015 # available pretty much immediately. UUID unchanged.
3016 # - On success, it will be respawed after the reboot (hopefully),
3017 # with a different UUID.
3018 #
3019 fRc = False;
3020 iStart = base.timestampMilli();
3021
3022 # Get UUID.
3023 cMsTimeout2 = min(60000, cMsTimeout);
3024 sUuidBefore = self.txsUuid(oSession, oTxsSession, self.adjustTimeoutMs(cMsTimeout2, 60000));
3025 if sUuidBefore is not False:
3026 # Reboot.
3027 cMsElapsed = base.timestampMilli() - iStart;
3028 cMsTimeout2 = cMsTimeout - cMsElapsed;
3029 fRc = self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncReboot,
3030 (self.adjustTimeoutMs(cMsTimeout2, 60000), False));
3031 if fRc is True:
3032 # Reconnect.
3033 if fNatForwardingForTxs is True:
3034 self.sleep(22); # NAT fudge - Two fixes are wanted: 1. TXS connect retries. 2. Main API reboot/reset hint.
3035 cMsElapsed = base.timestampMilli() - iStart;
3036 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, cMsTimeout - cMsElapsed, fNatForwardingForTxs);
3037 if fRc is True:
3038 # Check the UUID.
3039 cMsElapsed = base.timestampMilli() - iStart;
3040 cMsTimeout2 = min(60000, cMsTimeout - cMsElapsed);
3041 sUuidAfter = self.txsDoTask(oSession, oTxsSession, oTxsSession.asyncUuid,
3042 (self.adjustTimeoutMs(cMsTimeout2, 60000), False));
3043 if sUuidBefore is not False:
3044 if sUuidAfter != sUuidBefore:
3045 reporter.log('The guest rebooted (UUID %s -> %s)' % (sUuidBefore, sUuidAfter))
3046
3047 # Do CD wait if specified.
3048 if fCdWait:
3049 fRc = self.txsCdWait(oSession, oTxsSession, cMsCdWait, sFileCdWait);
3050 if fRc is not True:
3051 reporter.error('txsRebootAndReconnectViaTcp: txsCdWait failed');
3052 else:
3053 reporter.error('txsRebootAndReconnectViaTcp: failed to get UUID (after)');
3054 else:
3055 reporter.error('txsRebootAndReconnectViaTcp: did not reboot (UUID %s)' % (sUuidBefore,));
3056 else:
3057 reporter.error('txsRebootAndReconnectViaTcp: txsDoConnectViaTcp failed');
3058 else:
3059 reporter.error('txsRebootAndReconnectViaTcp: reboot failed');
3060 else:
3061 reporter.error('txsRebootAndReconnectViaTcp: failed to get UUID (before)');
3062 return (fRc, oTxsSession);
3063
3064 # pylint: disable=R0914,R0913
3065
3066 def txsRunTest(self, oTxsSession, sTestName, cMsTimeout, sExecName, asArgs = (), asAddEnv = (), sAsUser = ""):
3067 """
3068 Executes the specified test task, waiting till it completes or times out.
3069
3070 The VM session (if any) must be in the task list.
3071
3072 Returns True if we executed the task and nothing abnormal happend.
3073 Query the process status from the TXS session.
3074
3075 Returns False if some unexpected task was signalled or we failed to
3076 submit the job.
3077 """
3078 reporter.testStart(sTestName);
3079 reporter.log2('txsRunTest: cMsTimeout=%u sExecName=%s asArgs=%s' % (cMsTimeout, sExecName, asArgs));
3080
3081 # Submit the job.
3082 fRc = False;
3083 if oTxsSession.asyncExec(sExecName, asArgs, asAddEnv, sAsUser, cMsTimeout = self.adjustTimeoutMs(cMsTimeout)):
3084 self.addTask(oTxsSession);
3085
3086 # Wait for the job to complete.
3087 while True:
3088 oTask = self.waitForTasks(cMsTimeout + 1);
3089 if oTask is None:
3090 reporter.log('txsRunTest: waitForTasks timed out');
3091 break;
3092 if oTask is oTxsSession:
3093 fRc = True;
3094 reporter.log('txsRunTest: isSuccess=%s getResult=%s' % (oTxsSession.isSuccess(), oTxsSession.getResult()));
3095 break;
3096 if not self.handleTask(oTask, 'txsRunTest'):
3097 break;
3098
3099 self.removeTask(oTxsSession);
3100 if not oTxsSession.pollTask():
3101 oTxsSession.cancelTask();
3102 else:
3103 reporter.error('txsRunTest: asyncExec failed');
3104
3105 reporter.testDone();
3106 return fRc;
3107
3108 def txsRunTestRedirectStd(self, oTxsSession, sTestName, cMsTimeout, sExecName, asArgs = (), asAddEnv = (), sAsUser = "",
3109 oStdIn = '/dev/null', oStdOut = '/dev/null', oStdErr = '/dev/null', oTestPipe = '/dev/null'):
3110 """
3111 Executes the specified test task, waiting till it completes or times out,
3112 redirecting stdin, stdout and stderr to the given objects.
3113
3114 The VM session (if any) must be in the task list.
3115
3116 Returns True if we executed the task and nothing abnormal happend.
3117 Query the process status from the TXS session.
3118
3119 Returns False if some unexpected task was signalled or we failed to
3120 submit the job.
3121 """
3122 reporter.testStart(sTestName);
3123 reporter.log2('txsRunTestRedirectStd: cMsTimeout=%u sExecName=%s asArgs=%s' % (cMsTimeout, sExecName, asArgs));
3124
3125 # Submit the job.
3126 fRc = False;
3127 if oTxsSession.asyncExecEx(sExecName, asArgs, asAddEnv, oStdIn, oStdOut, oStdErr,
3128 oTestPipe, sAsUser, cMsTimeout = self.adjustTimeoutMs(cMsTimeout)):
3129 self.addTask(oTxsSession);
3130
3131 # Wait for the job to complete.
3132 while True:
3133 oTask = self.waitForTasks(cMsTimeout + 1);
3134 if oTask is None:
3135 reporter.log('txsRunTestRedirectStd: waitForTasks timed out');
3136 break;
3137 if oTask is oTxsSession:
3138 fRc = True;
3139 reporter.log('txsRunTestRedirectStd: isSuccess=%s getResult=%s'
3140 % (oTxsSession.isSuccess(), oTxsSession.getResult()));
3141 break;
3142 if not self.handleTask(oTask, 'txsRunTestRedirectStd'):
3143 break;
3144
3145 self.removeTask(oTxsSession);
3146 if not oTxsSession.pollTask():
3147 oTxsSession.cancelTask();
3148 else:
3149 reporter.error('txsRunTestRedirectStd: asyncExec failed');
3150
3151 reporter.testDone();
3152 return fRc;
3153
3154 def txsRunTest2(self, oTxsSession1, oTxsSession2, sTestName, cMsTimeout,
3155 sExecName1, asArgs1,
3156 sExecName2, asArgs2,
3157 asAddEnv1 = (), sAsUser1 = '', fWithTestPipe1 = True,
3158 asAddEnv2 = (), sAsUser2 = '', fWithTestPipe2 = True):
3159 """
3160 Executes the specified test tasks, waiting till they complete or
3161 times out. The 1st task is started after the 2nd one.
3162
3163 The VM session (if any) must be in the task list.
3164
3165 Returns True if we executed the task and nothing abnormal happend.
3166 Query the process status from the TXS sessions.
3167
3168 Returns False if some unexpected task was signalled or we failed to
3169 submit the job.
3170 """
3171 reporter.testStart(sTestName);
3172
3173 # Submit the jobs.
3174 fRc = False;
3175 if oTxsSession1.asyncExec(sExecName1, asArgs1, asAddEnv1, sAsUser1, fWithTestPipe1, '1-',
3176 self.adjustTimeoutMs(cMsTimeout)):
3177 self.addTask(oTxsSession1);
3178
3179 self.sleep(2); # fudge! grr
3180
3181 if oTxsSession2.asyncExec(sExecName2, asArgs2, asAddEnv2, sAsUser2, fWithTestPipe2, '2-',
3182 self.adjustTimeoutMs(cMsTimeout)):
3183 self.addTask(oTxsSession2);
3184
3185 # Wait for the jobs to complete.
3186 cPendingJobs = 2;
3187 while True:
3188 oTask = self.waitForTasks(cMsTimeout + 1);
3189 if oTask is None:
3190 reporter.log('txsRunTest2: waitForTasks timed out');
3191 break;
3192
3193 if oTask is oTxsSession1 or oTask is oTxsSession2:
3194 if oTask is oTxsSession1: iTask = 1;
3195 else: iTask = 2;
3196 reporter.log('txsRunTest2: #%u - isSuccess=%s getResult=%s' \
3197 % (iTask, oTask.isSuccess(), oTask.getResult()));
3198 self.removeTask(oTask);
3199 cPendingJobs -= 1;
3200 if cPendingJobs <= 0:
3201 fRc = True;
3202 break;
3203
3204 elif not self.handleTask(oTask, 'txsRunTest'):
3205 break;
3206
3207 self.removeTask(oTxsSession2);
3208 if not oTxsSession2.pollTask():
3209 oTxsSession2.cancelTask();
3210 else:
3211 reporter.error('txsRunTest2: asyncExec #2 failed');
3212
3213 self.removeTask(oTxsSession1);
3214 if not oTxsSession1.pollTask():
3215 oTxsSession1.cancelTask();
3216 else:
3217 reporter.error('txsRunTest2: asyncExec #1 failed');
3218
3219 reporter.testDone();
3220 return fRc;
3221
3222 # pylint: enable=R0914,R0913
3223
Note: See TracBrowser for help on using the repository browser.

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