Bug 551256 - 'Automate VMWare recording over mochitests'. r=ted, a=dholbert for CLOSED TREE
authorBen Turner <bent.mozilla@gmail.com>
Mon, 15 Mar 2010 14:44:29 -0700
changeset 39473 a8e7a2ba98fff8916d478a3ede0abf8d91bf8137
parent 39472 99ba38320cbe3a127f0b37fb4b6a1a9e302308a7
child 39474 69aa98ba272b3ec5194309d95e892496296c0e6a
push idunknown
push userunknown
push dateunknown
reviewersted, dholbert
bugs551256
milestone1.9.3a4pre
Bug 551256 - 'Automate VMWare recording over mochitests'. r=ted, a=dholbert for CLOSED TREE
build/win32/Makefile.in
build/win32/vmwarerecordinghelper/Makefile.in
build/win32/vmwarerecordinghelper/vmwarerecordinghelper.cpp
build/win32/vmwarerecordinghelper/vmwarerecordinghelper.def
testing/mochitest/Makefile.in
testing/mochitest/runtests.py.in
--- a/build/win32/Makefile.in
+++ b/build/win32/Makefile.in
@@ -38,17 +38,20 @@
 DEPTH = ../..
 topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 ifdef ENABLE_TESTS
-DIRS += crashinjectdll
+DIRS += \
+  crashinjectdll \
+  vmwarerecordinghelper \
+  $(NULL)
 
 PROGRAM = crashinject$(BIN_SUFFIX)
 USE_STATIC_LIBS = 1
 CPPSRCS = crashinject.cpp
 
 endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/build/win32/vmwarerecordinghelper/Makefile.in
@@ -0,0 +1,54 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is VMWare Recording Helper.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation
+#
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved.
+#
+# Contributor(s):
+#   Ben Turner <bent.mozilla@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH = ../../..
+topsrcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+LIBRARY_NAME = vmwarerecordinghelper
+DEFFILE = $(srcdir)/$(LIBRARY_NAME).def
+
+FORCE_SHARED_LIB = 1
+USE_STATIC_LIBS = 1
+
+CPPSRCS = $(LIBRARY_NAME).cpp
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/build/win32/vmwarerecordinghelper/vmwarerecordinghelper.cpp
@@ -0,0 +1,67 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is VMWare Recording Helper.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * The following code comes from "Starting and Stopping Recording of Virtual
+ * Machine Activity from Within the Guest":
+ *
+ *   http://kb.vmware.com/selfservice/documentLink.do?externalID=1001401
+ */
+
+void __cdecl
+StartRecording()
+{
+  __asm {
+    mov eax, 564d5868h
+    mov ebx, 1
+    mov cx, 47
+    mov dx, 5658h
+    in eax, dx
+  }
+}
+
+void __cdecl
+StopRecording()
+{
+  __asm {
+    mov eax, 564d5868h
+    mov ebx, 2
+    mov cx, 47
+    mov dx, 5658h
+    in eax, dx 
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/win32/vmwarerecordinghelper/vmwarerecordinghelper.def
@@ -0,0 +1,4 @@
+LIBRARY vmwarerecordinghelper
+EXPORTS
+     StartRecording
+     StopRecording
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -100,16 +100,17 @@ TEST_HARNESS_BINS := \
   certutil$(BIN_SUFFIX) \
   pk12util$(BIN_SUFFIX) \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 TEST_HARNESS_BINS += \
   crashinject$(BIN_SUFFIX) \
   crashinjectdll$(DLL_SUFFIX) \
+  vmwarerecordinghelper$(DLL_SUFFIX) \
   $(NULL)
 endif
 
 ifeq ($(OS_ARCH),Darwin)
 TEST_HARNESS_BINS += fix_macosx_stack.py
 endif
 
 ifeq ($(OS_ARCH),Linux)
--- a/testing/mochitest/runtests.py.in
+++ b/testing/mochitest/runtests.py.in
@@ -51,16 +51,18 @@ import time
 import shutil
 from urllib import quote_plus as encodeURIComponent
 import urllib2
 import commands
 from automation import Automation
 from automationutils import *
 import tempfile
 
+VMWARE_RECORDING_HELPER_BASENAME = "vmwarerecordinghelper"
+
 #######################
 # COMMANDLINE OPTIONS #
 #######################
 
 class MochitestOptions(optparse.OptionParser):
   """Parses Mochitest commandline options."""
   def __init__(self, automation, scriptdir, **kwargs):
     self._automation = automation
@@ -200,16 +202,22 @@ class MochitestOptions(optparse.OptionPa
     defaults["extraProfileFiles"] = []
 
     self.add_option("--profile-path", action = "store",
                     type = "string", dest = "profilePath",
                     help = "Directory where the profile will be stored."
                            "This directory will be deleted after the tests are finished")
     defaults["profilePath"] = tempfile.mkdtemp()
 
+    self.add_option("--use-vmware-recording",
+                    action = "store_true", dest = "vmwareRecording",
+                    help = "enables recording while the application is running "
+                           "inside a VMware Workstation 7.0 or later VM")
+    defaults["vmwareRecording"] = False
+
     # -h, --help are automatically handled by OptionParser
 
     self.set_defaults(**defaults)
 
     usage = """\
 Usage instructions for runtests.py.
 All arguments are optional.
 If --chrome is specified, chrome tests will be run instead of web content tests.
@@ -253,16 +261,26 @@ See <http://mochikit.com/doc/html/MochiK
     options.utilityPath = mochitest.getFullPath(options.utilityPath)
     options.certPath = mochitest.getFullPath(options.certPath)
     if options.symbolsPath:
       options.symbolsPath = mochitest.getFullPath(options.symbolsPath)
 
     options.webServer = self._automation.DEFAULT_WEB_SERVER
     options.httpPort = self._automation.DEFAULT_HTTP_PORT
     options.sslPort = self._automation.DEFAULT_SSL_PORT
+
+    if options.vmwareRecording:
+      if not self._automation.IS_WIN32:
+        self.error("use-vmware-recording is only supported on Windows.")
+      mochitest.vmwareHelperPath = os.path.join(
+        options.utilityPath, VMWARE_RECORDING_HELPER_BASENAME + ".dll")
+      if not os.path.exists(mochitest.vmwareHelperPath):
+        self.error("%s not found, cannot automate VMWare recording." %
+                   mochitest.vmwareHelperPath)
+
     return options
 
 
 #######################
 # HTTP SERVER SUPPORT #
 #######################
 
 class MochitestServer:
@@ -329,17 +347,18 @@ class MochitestServer:
 
 class Mochitest(object):
   # Path to the test script on the server
   TEST_PATH = "/tests/"
   CHROME_PATH = "/redirect.html";
   A11Y_PATH = "/redirect-a11y.html"
   urlOpts = []
   runSSLTunnel = True
- 
+  vmwareHelper = None
+
   oldcwd = os.getcwd()
 
   def __init__(self, automation):
     self.automation = automation
 
     # Max time in seconds to wait for server startup before tests will fail -- if
     # this seems big, it's mostly for debug machines where cold startup
     # (particularly after a build) takes forever.
@@ -481,16 +500,46 @@ class Mochitest(object):
       if options.shuffle:
         self.urlOpts.append("shuffle=1")
 
   def cleanup(self, manifest, options):
     """ remove temporary files and profile """
     os.remove(manifest)
     shutil.rmtree(options.profilePath)
 
+  def startVMWareRecording(self, options):
+    """ starts recording inside VMware VM using the recording helper dll """
+    assert(self.automation.IS_WIN32)
+    from ctypes import cdll
+    self.vmwareHelper = cdll.LoadLibrary(self.vmwareHelperPath)
+    if self.vmwareHelper is None:
+      self.automation.log.warning("WARNING | runtests.py | Failed to load "
+                                  "VMWare recording helper")
+      return
+    self.automation.log.info("INFO | runtests.py | Starting VMWare recording.")
+    try:
+      self.vmwareHelper.StartRecording()
+    except Exception, e:
+      self.automation.log.warning("WARNING | runtests.py | Failed to start "
+                                  "VMWare recording: (%s)" % str(e))
+      self.vmwareHelper = None
+
+  def stopVMWareRecording(self):
+    """ stops recording inside VMware VM using the recording helper dll """
+    assert(self.automation.IS_WIN32)
+    if self.vmwareHelper is not None:
+      self.automation.log.info("INFO | runtests.py | Stopping VMWare "
+                               "recording.")
+      try:
+        self.vmwareHelper.StopRecording()
+      except Exception, e:
+        self.automation.log.warning("WARNING | runtests.py | Failed to stop "
+                                    "VMWare recording: (%s)" % str(e))
+      self.vmwareHelper = None
+
   def runTests(self, options):
     """ Prepare, configure, run tests and cleanup """
     debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs,
                       options.debuggerInteractive);
 
     self.leak_report_file = os.path.join(options.profilePath, "runtests_leaks.log")
 
     browserEnv = self.buildBrowserEnv(options)
@@ -515,27 +564,34 @@ class Mochitest(object):
 
     # then again to actually run mochitest
     if options.timeout:
       timeout = options.timeout + 30
     elif not options.autorun:
       timeout = None
     else:
       timeout = 330.0 # default JS harness timeout is 300 seconds
+
+    if options.vmwareRecording:
+      self.startVMWareRecording(options);
+
     self.automation.log.info("INFO | runtests.py | Running tests: start.\n")
     status = self.automation.runApp(testURL, browserEnv, options.app,
                                 options.profilePath, options.browserArgs,
                                 runSSLTunnel = self.runSSLTunnel,
                                 utilityPath = options.utilityPath,
                                 xrePath = options.xrePath,
                                 certPath=options.certPath,
                                 debuggerInfo=debuggerInfo,
                                 symbolsPath=options.symbolsPath,
                                 timeout = timeout)
 
+    if options.vmwareRecording:
+      self.stopVMWareRecording();
+
     self.stopWebServer(options)
     processLeakLog(self.leak_report_file, options.leakThreshold)
     self.automation.log.info("\nINFO | runtests.py | Running tests: end.")
 
     self.cleanup(manifest, options)
     return status
 
   def makeTestConfig(self, options):