#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
VMM Guest OS boot tests.
"""
__copyright__ = \
"""
Copyright (C) 2010-2014 Oracle Corporation
This file is part of VirtualBox Open Source Edition (OSE), as
available from http://www.virtualbox.org. This file is free software;
you can redistribute it and/or modify it under the terms of the GNU
General Public License (GPL) as published by the Free Software
Foundation, in version 2 as it comes in the "COPYING" file of the
VirtualBox OSE distribution. VirtualBox OSE is distributed in the
hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
The contents of this file may alternatively be used under the terms
of the Common Development and Distribution License Version 1.0
(CDDL) only, as it comes in the "COPYING.CDDL" file of the
VirtualBox OSE distribution, in which case the provisions of the
CDDL are applicable instead of those of the GPL.
You may elect to license modified versions of this file under the
terms and conditions of either the GPL or the CDDL or both.
"""
__version__ = "$Revision$"
# Standard Python imports.
import os
import sys
import time
# Only the main script needs to modify the path.
try: __file__
except: __file__ = sys.argv[0]
g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(g_ksValidationKitDir)
# Validation Kit imports.
from testdriver import vbox
from testdriver import base
from testdriver import reporter
from testdriver import vboxcon
class tdGuestOsBootTest1(vbox.TestDriver):
"""
VMM Unit Tests Set.
Scenario:
- Create VM that corresponds to Guest OS pre-installed on selected HDD
- Start VM and wait for TXS server connection (which is started after Guest successfully booted)
"""
ksSataController = 'SATA Controller'
ksIdeController = 'IDE Controller'
# VM parameters required to run HDD image.
# Format: { HDD image filename: (sKind, HDD controller type) }
kaoVmParams = {
't-win80.vdi': ( 'Windows 8 (64 bit)', ksSataController ),
}
# List of platforms which are able to suspend and resume host automatically.
# In order to add new platform, self._SuspendResume() should be adapted.
kasSuspendAllowedPlatforms = ( 'darwin' )
kcMsVmStartLimit = 5 * 60000
kcMsVmShutdownLimit = 1 * 60000
def __init__(self):
"""
Reinitialize child class instance.
"""
vbox.TestDriver.__init__(self)
self.sVmName = 'TestVM'
self.sHddName = None
self.sHddPathBase = os.path.join(self.sResourcePath, '4.2', 'nat', 'win80')
self.oVM = None
# TODO: that should be moved to some common place
self.fEnableIOAPIC = True
self.cCpus = 1
self.fEnableNestedPaging = True
self.fEnablePAE = False
self.fSuspendHost = False
self.cSecSuspendTime = 60
self.cShutdownIters = 1
self.fExtraVm = False
self.sExtraVmName = "TestVM-Extra"
self.oExtraVM = None
self.fLocalCatch = False
#
# Overridden methods.
#
def showUsage(self):
"""
Extend usage info
"""
rc = vbox.TestDriver.showUsage(self)
reporter.log(' --boot-hdd <HDD image file name>')
reporter.log(' --cpus <# CPUs>')
reporter.log(' --no-ioapic')
reporter.log(' --no-nested-paging')
reporter.log(' --pae')
reporter.log(' --suspend-host')
reporter.log(' --suspend-time <sec>')
reporter.log(' --shutdown-iters <# iters>')
reporter.log(' --extra-vm')
reporter.log(' --local-catch')
return rc
def parseOption(self, asArgs, iArg):
"""
Extend standard options set
"""
if asArgs[iArg] == '--boot-hdd':
iArg += 1
if iArg >= len(asArgs): raise base.InvalidOption('The "--boot-hdd" option requires an argument')
self.sHddName = asArgs[iArg]
elif asArgs[iArg] == '--cpus':
iArg += 1
if iArg >= len(asArgs): raise base.InvalidOption('The "--cpus" option requires an argument')
self.cCpus = int(asArgs[iArg])
elif asArgs[iArg] == '--no-ioapic':
self.fEnableIOAPIC = False
elif asArgs[iArg] == '--no-nested-paging':
self.fEnableNestedPaging = False
elif asArgs[iArg] == '--pae':
self.fEnablePAE = True
elif asArgs[iArg] == '--suspend-host':
self.fSuspendHost = True
elif asArgs[iArg] == '--suspend-time':
iArg += 1
if iArg >= len(asArgs): raise base.InvalidOption('The "--suspend-time" option requires an argument')
self.cSecSuspendTime = int(asArgs[iArg])
elif asArgs[iArg] == '--shutdown-iters':
iArg += 1
if iArg >= len(asArgs): raise base.InvalidOption('The "--shutdown-iters" option requires an argument')
self.cShutdownIters = int(asArgs[iArg])
elif asArgs[iArg] == '--extra-vm':
self.fExtraVm = True
elif asArgs[iArg] == '--local-catch':
self.fLocalCatch = True
else:
return vbox.TestDriver.parseOption(self, asArgs, iArg)
return iArg + 1
def getResourceSet(self):
"""
Returns a set of file and/or directory names relative to
TESTBOX_PATH_RESOURCES.
"""
return [os.path.join(self.sHddPathBase, sRsrc) for sRsrc in self.kaoVmParams];
def _addVM(self, sVmName, sNicTraceFile=None):
"""
Create VM
"""
# Get VM params specific to HDD image
sKind, sController = self.kaoVmParams[self.sHddName]
# Create VM itself
eNic0AttachType = vboxcon.NetworkAttachmentType_NAT
sHddPath = os.path.join(self.sHddPathBase, self.sHddName)
assert os.path.isfile(sHddPath)
oVM = \
self.createTestVM(sVmName, 1, sKind=sKind, cCpus=self.cCpus,
eNic0AttachType=eNic0AttachType, sDvdImage = self.sVBoxValidationKitIso)
assert oVM is not None
oSession = self.openSession(oVM)
# Attach an HDD
fRc = oSession.attachHd(sHddPath, sController, fImmutable=True)
# Enable HW virt
fRc = fRc and oSession.enableVirtEx(True)
# Enable I/O APIC
fRc = fRc and oSession.enableIoApic(self.fEnableIOAPIC)
# Enable Nested Paging
fRc = fRc and oSession.enableNestedPaging(self.fEnableNestedPaging)
# Enable PAE
fRc = fRc and oSession.enablePae(self.fEnablePAE)
if (sNicTraceFile is not None):
fRc = fRc and oSession.setNicTraceEnabled(True, sNicTraceFile)
# Remote desktop
oSession.setupVrdp(True)
fRc = fRc and oSession.saveSettings()
fRc = fRc and oSession.close()
assert fRc is True
return oVM
def actionConfig(self):
"""
Configure pre-conditions.
"""
if not self.importVBoxApi():
return False
# Save time: do not start VM if there is no way to suspend host
if (self.fSuspendHost is True and sys.platform not in self.kasSuspendAllowedPlatforms):
reporter.log('Platform [%s] is not in the list of supported platforms' % sys.platform)
return False
assert self.sHddName is not None
if self.sHddName not in self.kaoVmParams:
reporter.log('Error: unknown HDD image specified: %s' % self.sHddName)
return False
if (self.fExtraVm is True):
self.oExtraVM = self._addVM(self.sExtraVmName)
self.oVM = self._addVM(self.sVmName)
return vbox.TestDriver.actionConfig(self)
def _SuspendResume(self, cSecTimeout):
"""
Put host into sleep and automatically resume it after specified timeout.
"""
fRc = False
if (sys.platform == 'darwin'):
tsStart = time.time()
fRc = os.system("/usr/bin/pmset relative wake %d" % self.cSecSuspendTime)
fRc |= os.system("/usr/bin/pmset sleepnow")
# Wait for host to wake up
while ((time.time() - tsStart) < self.cSecSuspendTime):
self.sleep(0.1)
return fRc == 0
def _waitKeyboardInterrupt(self):
"""
Idle loop until user press CTRL+C
"""
reporter.log('[LOCAL CATCH]: waiting for keyboard interrupt')
while (True):
try:
self.sleep(1)
except KeyboardInterrupt:
reporter.log('[LOCAL CATCH]: keyboard interrupt occurred')
break
def actionExecute(self):
"""
Execute the testcase itself.
"""
#self.logVmInfo(self.oVM)
reporter.testStart('SHUTDOWN GUEST')
cIter = 0
fRc = True
if (self.fExtraVm is True):
oExtraSession, oExtraTxsSession = self.startVmAndConnectToTxsViaTcp(self.sExtraVmName,
fCdWait=False,
cMsTimeout=self.kcMsVmStartLimit)
if oExtraSession is None or oExtraTxsSession is None:
reporter.error('Unable to start extra VM.')
if (self.fLocalCatch is True):
self._waitKeyboardInterrupt()
reporter.testDone()
return False
while (cIter < self.cShutdownIters):
cIter += 1
reporter.log("Starting iteration #%d." % cIter)
oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(self.sVmName,
fCdWait=False,
cMsTimeout=self.kcMsVmStartLimit)
if oSession is not None and oTxsSession is not None:
# Wait until guest reported success
reporter.log('Guest started. Connection to TXS service established.')
if (self.fSuspendHost is True):
reporter.log("Disconnect form TXS.")
fRc = fRc and self.txsDisconnect(oSession, oTxsSession)
if (fRc is not True):
reporter.log("Disconnect form TXS failed.")
else:
reporter.log('Put host to sleep and resume it automatically after %d seconds.' % self.cSecSuspendTime)
fRc = fRc and self._SuspendResume(self.cSecSuspendTime)
if (fRc is True):
reporter.log("Sleep/resume success.")
else:
reporter.log("Sleep/resume failed.")
reporter.log("Re-connect to TXS in 10 seconds.")
self.sleep(10)
(fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 2 * 60 * 10000)
if (fRc is not True):
reporter.log("Re-connect to TXS failed.")
if (fRc is True):
reporter.log('Attempt to shutdown guest.')
fRc = fRc and oTxsSession.syncShutdown(cMsTimeout=(4 * 60 * 1000))
if (fRc is True):
reporter.log('Shutdown request issued successfully.')
self.waitOnDirectSessionClose(self.oVM, self.kcMsVmShutdownLimit)
reporter.log('Shutdown %s.' % ('success' if fRc is True else 'failed'))
else:
reporter.error('Shutdown request failed.')
# Do not terminate failing VM in order to catch it.
if (fRc is not True and self.fLocalCatch is True):
self._waitKeyboardInterrupt()
break
fRc = fRc and self.terminateVmBySession(oSession)
reporter.log('VM terminated.')
else:
reporter.error('Guest did not start (iteration %d of %d)' % (cIter, self.cShutdownIters))
fRc = False
# Stop if fail
if (fRc is not True):
break
# Local catch at the end.
if (self.fLocalCatch is True):
reporter.log("Test completed. Waiting for user to press CTRL+C.")
self._waitKeyboardInterrupt()
if (self.fExtraVm is True):
fRc = fRc and self.terminateVmBySession(oExtraSession)
reporter.testDone()
return fRc is True
if __name__ == '__main__':
sys.exit(tdGuestOsBootTest1().main(sys.argv))