VirtualBox

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

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

testboxcontroller.py,vbox.py: accept 'log/guest/kernel' logs. Drop the '/failure|success' suffix from the type.

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