VirtualBox

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

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

tdUnitTest1.py: We should set VBOX_USER_HOME too.

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