VirtualBox

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

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

ValidationKit: Query the guest stack for all VCPUs and add it to the misc info items

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