VirtualBox

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

Last change on this file since 61951 was 61951, checked in by vboxsync, 8 years ago

testdriver/vbox*.py: Oh, don't be 'smart' and use pollTask to check whether the VM needs powering off. Added needsPoweringOff to the session wrapper for doing that.

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