Bug 701076 - [hookup to make] Robotium integration into birch tree. r=blassey,bear
☠☠ backed out by 2ea7afaa47a9 ☠ ☠
authorJoel Maher <jmaher@mozilla.com>
Fri, 30 Dec 2011 15:57:34 -0500
changeset 86033 04ef7f5644504e96208a12e50d1a39471b7c4441
parent 86032 632f07583bd8aae01cef0faaf6d3f8afd5c33ceb
child 86034 9dda4ea46da1821c8259eadf279549b90354cdca
push id674
push userffxbld
push dateTue, 13 Mar 2012 21:17:50 +0000
treeherdermozilla-beta@e3c4c92dec31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey, bear
bugs701076
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 701076 - [hookup to make] Robotium integration into birch tree. r=blassey,bear
build/Makefile.in
build/mobile/robocop/Makefile.in
testing/mochitest/Makefile.in
testing/mochitest/roboextender/Makefile.in
testing/mochitest/roboextender/bootstrap.js
testing/mochitest/roboextender/install.rdf
testing/mochitest/runtestsremote.py
testing/testsuite-targets.mk
toolkit/mozapps/installer/packager.mk
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -57,16 +57,17 @@ DIRS += pgo
 
 ifdef ENABLE_TESTS
   DIRS += autoconf/test
 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
   DIRS += mobile/sutagent/android \
           mobile/sutagent/android/watcher \
           mobile/sutagent/android/ffxcp \
           mobile/sutagent/android/fencp \
+          mobile/robocop \
           $(NULL)
 endif
 endif
 
 ifdef MOZ_APP_BASENAME
 DIST_FILES = application.ini
 
 ifdef LIBXUL_SDK
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -125,24 +125,21 @@ classes.dex: $(_JAVA_HARNESS)
 classes.dex: $(_JAVA_TESTS)
 	$(NSINSTALL) -D classes
 	$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(addprefix $(DEPTH)/mobile/android/base/tests/,$(_JAVA_TESTS))
 	$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH)
 
 robocop.ap_: AndroidManifest.xml
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -I . -S res -F $@ -J ./
 
-robocop-unsigned-unaligned.apk: robocop.ap_ classes.dex
-	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
-
-robocop-unaligned.apk: robocop-unsigned-unaligned.apk
-	cp robocop-unsigned-unaligned.apk $@
-	jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android $@ androiddebugkey
-
-robocop.apk: robocop-unaligned.apk
-	$(ZIPALIGN) -f -v 4 robocop-unaligned.apk $@
+robocop.apk: robocop.ap_ classes.dex
+	$(APKBUILDER) robocop-raw.apk -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
+ifdef JARSIGNER
+	$(JARSIGNER) robocop-raw.apk
+endif
+	$(ZIPALIGN) -f -v 4 robocop-raw.apk $@
 	cp $(TESTPATH)/robocop.ini robocop.ini
 	cp $(srcdir)/parse_ids.py parse_ids.py
 
 export::
 	$(NSINSTALL) -D res
 	@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/robocop/res && tar -xf -)
 
--- a/testing/mochitest/Makefile.in
+++ b/testing/mochitest/Makefile.in
@@ -46,16 +46,17 @@ include $(DEPTH)/config/autoconf.mk
 DIRS = \
   MochiKit \
   static \
   dynamic \
   tests \
   chrome \
   ssltunnel \
   specialpowers \
+  roboextender \
   $(NULL)
 
 
 NO_JS_MANIFEST = 1
 MOZ_CHROME_FILE_FORMAT = jar
 DIST_FILES = install.rdf
 
 # Used in install.rdf
@@ -77,16 +78,17 @@ include $(topsrcdir)/build/automation-bu
 		runtests.py \
 		automation.py \
 		runtestsremote.py \
 		runtestsvmware.py \
 		$(topsrcdir)/build/mobile/devicemanager.py \
 		$(topsrcdir)/build/mobile/devicemanagerADB.py \
 		$(topsrcdir)/build/mobile/devicemanagerSUT.py \
 		$(topsrcdir)/build/automationutils.py \
+		$(topsrcdir)/build/manifestparser.py \
 		$(topsrcdir)/build/mobile/remoteautomation.py \
 		gen_template.pl \
 		server.js \
 		harness-overlay.xul \
 		harness.xul \
 		browser-test-overlay.xul \
 		browser-test.js \
 		chrome-harness.js \
@@ -95,16 +97,20 @@ include $(topsrcdir)/build/automation-bu
 		$(topsrcdir)/build/pgo/server-locations.txt \
 		$(topsrcdir)/netwerk/test/httpserver/httpd.js \
 		mozprefs.js \
 		pywebsocket_wrapper.py \
  	 	plain-loop.html \
 		android.json \
 		$(NULL)	
 
+ifeq ($(MOZ_BUILD_APP),mobile/android)
+_SERV_FILES += $(topsrcdir)/mobile/android/base/tests/robocop.ini
+endif
+
 _PYWEBSOCKET_FILES = \
 		pywebsocket/standalone.py \
 		$(NULL)
 
 _MOD_PYWEBSOCKET_FILES = \
 		pywebsocket/mod_pywebsocket/__init__.py \
 		pywebsocket/mod_pywebsocket/common.py \
 		pywebsocket/mod_pywebsocket/dispatch.py \
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/roboextender/Makefile.in
@@ -0,0 +1,58 @@
+#
+# ***** 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 mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# 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@
+relativesrcdir  = testing/mochitest/roboextender
+
+include $(DEPTH)/config/autoconf.mk
+
+_TEST_FILES = \
+  bootstrap.js \
+  install.rdf \
+  $(NULL)
+
+TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions
+
+include $(topsrcdir)/config/rules.mk
+
+libs:: $(_TEST_FILES)
+	$(MKDIR) -p $(TEST_EXTENSIONS_DIR)/roboextender@mozilla.org
+	$(INSTALL) $(foreach f,$^,"$f") $(TEST_EXTENSIONS_DIR)/roboextender@mozilla.org/
+	
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/roboextender/bootstrap.js
@@ -0,0 +1,60 @@
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+function loadIntoWindow(window) {}
+function unloadFromWindow(window) {}
+
+function _sendMessageToJava (aMsg) {
+  let bridge = Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
+  return bridge.handleGeckoMessage(JSON.stringify(aMsg));
+};
+
+/*
+ bootstrap.js API
+*/
+var windowListener = {
+  onOpenWindow: function(aWindow) {
+    // Wait for the window to finish loading
+    let domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
+    domWindow.addEventListener("load", function() {
+      domWindow.removeEventListener("load", arguments.callee, false);
+      if (domWindow) {
+        domWindow.addEventListener("scroll", function(e) {
+          let message = {
+            gecko: {
+              type: 'robocop:scroll',
+              y: XPCNativeWrapper.unwrap(e.target).documentElement.scrollTop,
+              height: XPCNativeWrapper.unwrap(e.target).documentElement.scrollHeight,
+              cheight: XPCNativeWrapper.unwrap(e.target).documentElement.clientHeight,
+            }
+          };
+          let retVal = _sendMessageToJava(message);
+        });
+      }
+    }, false);
+  },
+  onCloseWindow: function(aWindow) { },
+  onWindowTitleChange: function(aWindow, aTitle) { }
+};
+
+function startup(aData, aReason) {
+  let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+
+  // Load into any new windows
+  wm.addListener(windowListener);
+}
+
+function shutdown(aData, aReason) {
+  // When the application is shutting down we normally don't have to clean up any UI changes
+  if (aReason == APP_SHUTDOWN) return;
+
+  let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+  let obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+
+  // Stop watching for new windows
+  wm.removeListener(windowListener);
+}
+
+function install(aData, aReason) { }
+function uninstall(aData, aReason) { }
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/roboextender/install.rdf
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+    <Description about="urn:mozilla:install-manifest">
+        <em:id>roboextender@mozilla.org</em:id>
+        <em:type>2</em:type>
+        <em:name>Robocop Extender</em:name>
+        <em:version>1.0</em:version>
+        <em:bootstrap>true</em:bootstrap>
+        <em:creator>Joel Maher</em:creator>
+        <em:targetApplication>
+            <Description>
+               <em:id>toolkit@mozilla.org</em:id>
+               <em:minVersion>10.0</em:minVersion>
+               <em:maxVersion>*</em:maxVersion>
+            </Description>
+        </em:targetApplication>
+    </Description>
+</RDF>
+
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -44,16 +44,17 @@ sys.path.insert(0, os.path.abspath(os.pa
 
 from automation import Automation
 from remoteautomation import RemoteAutomation
 from runtests import Mochitest
 from runtests import MochitestOptions
 from runtests import MochitestServer
 
 import devicemanager, devicemanagerADB, devicemanagerSUT
+import manifestparser
 
 class RemoteOptions(MochitestOptions):
 
     def __init__(self, automation, scriptdir, **kwargs):
         defaults = {}
         MochitestOptions.__init__(self, automation, scriptdir)
 
         self.add_option("--remote-app-path", action="store",
@@ -101,16 +102,21 @@ class RemoteOptions(MochitestOptions):
                     help = "ip address where the remote web server is hosted at")
         defaults["sslPort"] = automation.DEFAULT_SSL_PORT
 
         self.add_option("--pidfile", action = "store",
                     type = "string", dest = "pidFile",
                     help = "name of the pidfile to generate")
         defaults["pidFile"] = ""
 
+        self.add_option("--robocop", action = "store",
+                    type = "string", dest = "robocop",
+                    help = "use when running robotium tests on native UI")
+        defaults["robocop"] = ""
+
         defaults["remoteTestRoot"] = None
         defaults["logFile"] = "mochitest.log"
         defaults["autorun"] = True
         defaults["closeWhenDone"] = True
         defaults["testPath"] = ""
         defaults["app"] = None
 
         self.set_defaults(**defaults)
@@ -307,17 +313,17 @@ class MochiRemote(Mochitest):
         return logFile
 
 def main():
     scriptdir = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
     dm_none = devicemanagerADB.DeviceManagerADB()
     auto = RemoteAutomation(dm_none, "fennec")
     parser = RemoteOptions(auto, scriptdir)
     options, args = parser.parse_args()
-    if (options.dm_trans == "adb"):
+    if (options.dm_trans == "adb" or options.robocop):
         if (options.deviceIP):
             dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort)
         else:
             dm = dm_none
     else:
          dm = devicemanagerSUT.DeviceManagerSUT(options.deviceIP, options.devicePort)
     auto.setDeviceManager(dm)
     options = parser.verifyRemoteOptions(options, auto)
@@ -340,22 +346,54 @@ def main():
     logParent = os.path.dirname(options.remoteLogFile)
     dm.mkDir(logParent);
     auto.setRemoteLog(options.remoteLogFile)
     auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
 
     procName = options.app.split('/')[-1]
     if (dm.processExist(procName)):
       dm.killProcess(procName)
+    
+    if (options.robocop):
+      mp = manifestparser.TestManifest(strict=False)
+      # TODO: pull this in dynamically
+      mp.read('robocop.ini')
+      robocop_tests = mp.active_tests(exists=False)
 
-    try:
-      retVal = mochitest.runTests(options)
-    except:
-      print "TEST-UNEXPECTED-ERROR | | Exception caught while running tests."
+      fHandle = open("robotium.config", "w")
+      fHandle.write("profile=%s\n" % (mochitest.remoteProfile))
+      fHandle.write("logfile=%s\n" % (options.remoteLogFile))
+      fHandle.close()
+      deviceRoot = dm.getDeviceRoot()
+      
+      # Note, we are pushing to /sdcard since we have this location hard coded in robocop
+      dm.pushFile("robotium.config", "/sdcard/robotium.config")
+      dm.pushFile(os.path.abspath(options.robocop + "/fennec_ids.txt"), "/sdcard/fennec_ids.txt")
+      options.extraPrefs.append('robocop.logfile="%s/robocop.log"' % deviceRoot)
+
+      manifest = mochitest.buildProfile(options)
+      mochitest.startWebServer(options)
+
+      if (options.dm_trans == 'adb'):
+        dm.checkCmd(["install", "-r", os.path.join(options.robocop, "robocop.apk")])
+        for test in robocop_tests:
+          cmd = ["shell", "am", "instrument", "-w", "-e", "class"]
+          cmd.append("%s.tests.%s" % (options.app, test['name']))
+          cmd.append("org.mozilla.roboexample.test/android.test.InstrumentationTestRunner")
+          retVal = dm.checkCmd(cmd)
+      else:
+        # SUTAgent needs to install robocop and not crash when we launch robocop.
+        retVal = dm.launchProcess(["am", "instrument", "-w", "org.mozilla.roboexample.test/android.test.InstrumentationTestRunner"])
       mochitest.stopWebServer(options)
-      mochitest.stopWebSocketServer(options)
-      sys.exit(1)
+    else:
+      try:
+        retVal = mochitest.runTests(options)
+      except:
+        print "TEST-UNEXPECTED-ERROR | | Exception caught while running tests."
+        mochitest.stopWebServer(options)
+        mochitest.stopWebSocketServer(options)
+        sys.exit(1)
       
     sys.exit(retVal)
         
 if __name__ == "__main__":
     main()
 
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -69,16 +69,23 @@ RUN_MOCHITEST = \
 
 RUN_MOCHITEST_REMOTE = \
 	rm -f ./$@.log && \
 	$(PYTHON) _tests/testing/mochitest/runtestsremote.py --autorun --close-when-done \
 	  --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \
 	  --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
 	  $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
 
+RUN_MOCHITEST_ROBOTIUM = \
+  rm -f ./$@.log && \
+  $(PYTHON) _tests/testing/mochitest/runtestsremote.py --robocop ../../../build/mobile/robocop \
+    --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=adb \
+    --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \
+    $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS)
+
 ifndef NO_FAIL_ON_TEST_ERRORS
 define CHECK_TEST_ERROR
   @errors=`grep "TEST-UNEXPECTED-" $@.log` ;\
   if test "$$errors" ; then \
 	  echo "$@ failed:"; \
 	  echo "$$errors"; \
 	  exit 1; \
   else \
@@ -90,16 +97,24 @@ endif
 mochitest-remote: DM_TRANS?=adb
 mochitest-remote:
 	@if test -f ${MOZ_HOST_BIN}/xpcshell && [ "${TEST_DEVICE}" != "usb" -o "$(DM_TRANS)" = "adb" ]; \
           then $(RUN_MOCHITEST_REMOTE); \
         else \
           echo "please prepare your host with environment variables for TEST_DEVICE and MOZ_HOST_BIN"; \
         fi
 
+mochitest-robotium: DM_TRANS?=adb
+mochitest-robotium:
+	@if test -f ${MOZ_HOST_BIN}/xpcshell && [ "${TEST_DEVICE}" != "usb" -o "$(DM_TRANS)" = "adb" ]; \
+          then $(RUN_MOCHITEST_ROBOTIUM); \
+        else \
+          echo "please prepare your host with environment variables for TEST_DEVICE and MOZ_HOST_BIN"; \
+        fi
+
 mochitest-plain:
 	$(RUN_MOCHITEST)
 	$(CHECK_TEST_ERROR)
 
 # Allow mochitest-1 ... mochitest-5 for developer ease
 mochitest-1 mochitest-2 mochitest-3 mochitest-4 mochitest-5: mochitest-%:
 	echo "mochitest: $* / 5"
 	$(RUN_MOCHITEST) --chunk-by-dir=4 --total-chunks=5 --this-chunk=$*
@@ -281,16 +296,21 @@ stage-xpcshell: make-stage-dir
 stage-jstests: make-stage-dir
 	$(MAKE) -C $(DEPTH)/js/src/tests stage-package
 
 stage-android: make-stage-dir
 	$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/sutAgentAndroid.apk $(PKG_STAGE)/bin
 	$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/watcher/Watcher.apk $(PKG_STAGE)/bin
 	$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/fencp/FenCP.apk $(PKG_STAGE)/bin
 	$(NSINSTALL) $(DEPTH)/build/mobile/sutagent/android/ffxcp/FfxCP.apk $(PKG_STAGE)/bin
+ifeq ($(MOZ_BUILD_APP),mobile/android)
+	$(NSINSTALL) $(DEPTH)/build/mobile/robocop/robocop.apk $(PKG_STAGE)/bin
+	$(PYTHON) $(DIST)/../build/mobile/robocop/parse_ids.py -i $(DEPTH)/mobile/android/base/R.java -o $(DEPTH)/build/mobile/robocop/fennec_ids.txt
+	$(NSINSTALL) $(DEPTH)/build/mobile/robocop/fennec_ids.txt $(PKG_STAGE)/bin
+endif
 
 stage-jetpack: make-stage-dir
 	$(NSINSTALL) $(topsrcdir)/testing/jetpack/jetpack-location.txt $(PKG_STAGE)/jetpack
 
 stage-firebug: make-stage-dir
 	$(MAKE) -C $(DEPTH)/testing/firebug stage-package
 
 stage-peptest: make-stage-dir
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -345,16 +345,17 @@ INNER_MAKE_PACKAGE	= \
     rm $(_ABS_DIST)/gecko.ap_ && \
     $(ZIP) -r9D $(_ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) && \
     $(ZIP) -0 $(_ABS_DIST)/gecko.ap_ $(OMNIJAR_NAME)) && \
   rm -f $(_ABS_DIST)/gecko.apk && \
   $(APKBUILDER) $(_ABS_DIST)/gecko.apk -v $(APKBUILDER_FLAGS) -z $(_ABS_DIST)/gecko.ap_ -f $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
   cp $(_ABS_DIST)/gecko.apk $(_ABS_DIST)/gecko-unsigned-unaligned.apk && \
   $(JARSIGNER) $(_ABS_DIST)/gecko.apk && \
   $(ZIPALIGN) -f -v 4 $(_ABS_DIST)/gecko.apk $(PACKAGE)
+
 INNER_UNMAKE_PACKAGE	= \
   mkdir $(MOZ_PKG_DIR) && \
   pushd $(MOZ_PKG_DIR) && \
   $(UNZIP) $(UNPACKAGE) && \
   mv lib/$(ABI_DIR)/libmozutils.so . && \
   mv lib/$(ABI_DIR)/*plugin-container* $(MOZ_CHILD_PROCESS_NAME) && \
   rm -rf lib/$(ABI_DIR) && \
   popd