summaryrefslogtreecommitdiffstats
path: root/test-framework/vmware/control.py
diff options
context:
space:
mode:
Diffstat (limited to 'test-framework/vmware/control.py')
-rw-r--r--test-framework/vmware/control.py220
1 files changed, 220 insertions, 0 deletions
diff --git a/test-framework/vmware/control.py b/test-framework/vmware/control.py
new file mode 100644
index 000000000..b24c33ea9
--- /dev/null
+++ b/test-framework/vmware/control.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+import ConfigParser, datetime, os, string, sys, time, platform
+import testcase, utils, result, virtualmachine
+from virtualmachine import VMException
+from xml.sax import make_parser
+from xml.sax.handler import ContentHandler
+
+class ControlException( Exception ):
+ def __init__( self, value ):
+ self.value = value
+ def __str__( self ):
+ return repr( self.value )
+
+class Handler( ContentHandler ):
+ def __init__( self, res ):
+ self._res = res
+ self._inResult = False
+ self._buf = ""
+
+ def startElement( self, name, attrs ):
+ self._inResult = False
+ if name == "result":
+ self._inResult = True
+ self._name = attrs['name']
+ self._status = attrs['status']
+
+ def endElement( self, name ):
+ if name == 'result':
+ trimmed = string.strip( self._buf )
+ if self._status == "passed":
+ stat = result.CheckerResult.Passed
+ else:
+ stat = result.CheckerResult.Failed
+ self._res.addCheckerResult( result.CheckerResult( self._name, stat, trimmed ) )
+ self._inResult = False
+
+ self._buf = ""
+
+ def characters( self, ch ):
+ if self._inResult:
+ self._buf += ch
+
+class Control:
+ def __init__( self, vmrun, checkerDir, source, reporter ):
+ self._vmrun = vmrun
+ self._checkerDir = checkerDir
+ self._vms = []
+ self._testcases = []
+ self._source = source
+ self._reporter = reporter
+ self._guiEnabled = True
+ self._createErrorSnapshots = False
+ self._hostType = ""
+ self._hostLocation = ""
+ self._hostUsername = ""
+ self._hostPassword = ""
+
+ def setGuiEnabled( self, usegui ):
+ self._guiEnabled = usegui
+ for i in self._vms:
+ i.setGuiEnabled( usegui )
+
+ def setCreateErrorSnapshots( self, createSnapshots ):
+ self._createErrorSnapshots = createSnapshots
+
+ def setRemoteHost( self, type, loc, user, pw ):
+ self._hostType = type
+ self._hostLocation = loc
+ self._hostUsername = user
+ self._hostPassword = pw
+ for vm in self._vms:
+ if not vm.isRemote():
+ vm.setRemoteHost( self._hostType, self._hostLocation, self._hostUsername, self._hostPassword )
+
+ def addVM( self, cfgpath ):
+ config = ConfigParser.SafeConfigParser()
+ config.read( cfgpath )
+ vm = virtualmachine.fromVMRunAndPath( self._vmrun, cfgpath )
+ vm.setGuiEnabled( self._guiEnabled )
+ if len( self._hostType ) > 0 and not vm.isRemote():
+ vm.setRemoteHost( self._hostType, self._hostLocation, self._hostUsername, self._hostPassword )
+ self._vms.append( vm )
+ #TODO catch/transform exceptions
+
+ def addTestCase( self, path ):
+ self._testcases.append( testcase.TestCase( path ) )
+
+
+ def run( self ):
+ while True:
+ try:
+ inst = self._source.nextInstaller()
+ if inst == None:
+ print( "** Installer source returned None, aborting" )
+ return
+ if inst.error:
+ raise ControlException( inst.error )
+ print( "** New installer: {0}".format( inst.path ) )
+ self.testInstaller( inst, inst.platform )
+ except KeyboardInterrupt:
+ raise
+ except:
+ self._reporter.reportException()
+
+ def testInstaller( self, inst, platform ):
+ for vm in self._vms:
+ if vm.ostype() != platform:
+ continue
+ for case in self._testcases:
+ if not case.supportsPlatform( platform ):
+ continue
+ res = result.Result()
+ try:
+ try:
+ res.setInstaller( inst )
+ res.setTestCase( case )
+ res.setVirtualMachine( vm )
+ res.testStarted()
+ self.run_test( inst.path, vm, case, res )
+ res.testFinished()
+ inst.markAsTested()
+ except KeyboardInterrupt:
+ raise
+ except:
+ res.addException()
+ finally:
+ self._reporter.reportResult( res )
+
+ def convertCheckerResults( self, filename, res ):
+ parser = make_parser()
+ parser.setContentHandler( Handler( res ) )
+ f = file( filename, 'rb' )
+ parser.parse( f )
+
+ def run_test( self, installerPath, vm, testcase, res ):
+ steps = testcase.steps()
+ if len( steps ) == 0:
+ raise ControlException( "No steps found for testcase {0}".format( testcase.name() ) )
+
+ revertStatus, _ = vm.revertToSnapshot()
+ if revertStatus != 0:
+ raise VMException( "Failed to revert to snapshot '{0}'".format( vm.snapshot() ) )
+
+
+ time.sleep( 5 ) # Trying to avoid a possible race between restore and start
+
+ vm.start()
+
+ try:
+ try:
+ vm.checkPythonInstalled()
+ wrapperpath = vm.copyToTemp( utils.execution_path( 'guest.py' ) )
+
+ for stepNum in range( len( steps ) ):
+ needSnapshot = False
+ step = steps[stepNum]
+ if stepNum == 0:
+ executableguestpath = vm.copyToTemp( installerPath )
+ else:
+ executableguestpath = testcase.maintenanceToolLocation()
+
+ outputFileName = 'output{0}.log'.format( stepNum )
+ outputpath = vm.mkTempPath( outputFileName )
+ scriptguestpath = vm.copyToTemp( step.installscript() )
+ timeout = step.timeout()
+ checkerguestpath = vm.copyToTemp( step.checkerTestDir(), "checkerTestDir{0}".format( stepNum ) ) if len( string.strip( step.checkerTestDir() ) ) > 0 else None
+ vm.command( 'Execute installer', "runProgramInGuest", "'{0}' '{1}' '{2}' '{3}' '{4}' --script '{5}'".format( vm.python(), wrapperpath, outputpath, timeout, executableguestpath, scriptguestpath ) )
+ vm.copyFromTemp( outputFileName, outputFileName )
+ r = ConfigParser.SafeConfigParser()
+ r.read( outputFileName )
+ try:
+ s = r.get( 'Result', 'ExitCode' )
+ exitCode = int( s )
+ except ValueError:
+ res.addInternalError( "Could not parse integer exit code from '{0}'".format( r.get( 'Result', 'ExitCode' ) ) )
+ exitCode = -1
+ try:
+ s = r.get( 'Result', 'ExecutionTime' )
+ executionTime = float( s )
+ except ValueError:
+ res.addInternalError( "Could not parse float execution time from '{0}'".format( r.get( 'Result', 'ExecutionTime' ) ) )
+ executionTime = 0.0
+
+ exitStatus = result.exitStatusFromString( r.get( 'Result', 'ExitStatus' ) )
+ instR = result.ExecutionResult( exitCode, exitStatus, executionTime )
+
+ if instR.hasError():
+ needSnapshot = True
+
+ checkerResults = []
+ if checkerguestpath and not instR.hasError():
+ if ( platform.system() == "Darwin" ):
+ # Have to sleep to work around VMware Fusion bug
+ time.sleep( 30 )
+ run_py = vm.copyToTemp( self._checkerDir ) + vm.pathSep() + "run.py"
+ if ( platform.system() == "Darwin" ):
+ # Have to sleep to work around VMware Fusion bug
+ time.sleep( 30 )
+ checkeroutputFileName = 'checker-output{0}.xml'.format( stepNum )
+ checkeroutput = vm.mkTempPath( checkeroutputFileName )
+ vm.command( 'Execute checker tests', "runProgramInGuest", "'{0}' '{1}' '{2}' -o '{3}' -p '{4}'".format( vm.python(), run_py, checkerguestpath, checkeroutput, testcase.targetDirectory() ) )
+ vm.copyFromTemp( checkeroutputFileName, checkeroutputFileName )
+ self.convertCheckerResults( localcheckeroutput, checkerResults )
+ if res.hasCheckerErrors():
+ needSnapshot = True
+ if self._createErrorSnapshots and needSnapshot:
+ snapshot = 'error-{0}-{1}'.format( datetime.datetime.now().strftime( '%Y%m%d_%H%M%S' ), utils.randomString( 4 ) )
+ status, _ = vm.createSnapshot( snapshot )
+ if status == 0:
+ res.setErrorSnapshot( snapshot )
+ else:
+ res.addInternalError( 'Could not create error snapshot "{0}"'.format( snapshot ) )
+ res.addStepResult( result.StepResult( instR, checkerResults ) )
+ #TODO handle timeouts?
+ finally:
+ vm.kill()
+ except e:
+ print( e )
+ res.addInternalError( str( e ) )
+ \ No newline at end of file