Bug 715309 - robocop needs to have a more uniform log format. r=gbrown
authorJoel Maher <jmaher@mozilla.com>
Sat, 07 Jan 2012 18:41:08 -0500
changeset 84010 8b1c24ce4537fdbd311f16f645d27975e54db80f
parent 84009 0d10b1ea459f1cc19a3f7db19090d4ec7db60415
child 84011 aea8ac101dfee2d5b406926d3f2ec833a11f2834
push id4680
push userjmaher@mozilla.com
push dateSat, 07 Jan 2012 23:45:20 +0000
treeherdermozilla-inbound@33359378d8f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgbrown
bugs715309
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 715309 - robocop needs to have a more uniform log format. r=gbrown
build/mobile/devicemanagerADB.py
build/mobile/remoteautomation.py
build/mobile/robocop/Assert.java.in
build/mobile/robocop/Driver.java.in
build/mobile/robocop/FennecNativeAssert.java.in
build/mobile/robocop/FennecNativeDriver.java.in
mobile/android/base/tests/BaseTest.java.in
mobile/android/base/tests/testPan.java.in
testing/mochitest/runtestsremote.py
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -253,16 +253,20 @@ class DeviceManagerADB(DeviceManager):
       parts = parts[2:]
     return self.launchProcess(parts, failIfRunning)
 
   # external function
   # returns:
   #  success: output filename
   #  failure: None
   def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
+    if cmd[0] == "am":
+      self.checkCmd(["shell"] + cmd)
+      return outputFile
+
     acmd = ["shell", "am","start"]
     cmd = ' '.join(cmd).strip()
     i = cmd.find(" ")
     # SUT identifies the URL by looking for :\\ -- another strategy to consider
     re_url = re.compile('^[http|file|chrome|about].*')
     last = cmd.rfind(" ")
     uri = ""
     args = ""
@@ -277,17 +281,17 @@ class DeviceManagerADB(DeviceManager):
     if args != "":
       acmd.append("args")
       acmd.append(args)
     if uri != "":
       acmd.append("-d")
       acmd.append(''.join(['\'',uri, '\'']));
     print acmd
     self.checkCmd(acmd)
-    return outputFile;
+    return outputFile
 
   # external function
   # returns:
   #  success: output from testagent
   #  failure: None
   def killProcess(self, appname):
     procs = self.getProcessList()
     for (pid, name, user) in procs:
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -117,16 +117,21 @@ class RemoteAutomation(Automation):
         except:
           print "WARNING: unable to remove directory: %s" % (dumpDir)
 
     def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
         # If remote profile is specified, use that instead
         if (self._remoteProfile):
             profileDir = self._remoteProfile
 
+        # Hack for robocop, if app & testURL == None and extraArgs contains the rest of the stuff, lets 
+        # assume extraArgs is all we need
+        if app == "am" and extraArgs[0] == "instrument":
+            return app, extraArgs
+ 
         cmd, args = Automation.buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs)
         # Remove -foreground if it exists, if it doesn't this just returns
         try:
             args.remove('-foreground')
         except:
             pass
 #TODO: figure out which platform require NO_EM_RESTART
 #        return app, ['--environ:NO_EM_RESTART=1'] + args
--- a/build/mobile/robocop/Assert.java.in
+++ b/build/mobile/robocop/Assert.java.in
@@ -37,17 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 package @ANDROID_PACKAGE_NAME@;
 
 public interface Assert {
   void dumpLog(String message);
   void setLogFile(String filename);
+  void setTestName(String testName);
 
+  void finalize();
   void ok(boolean condition, String name, String diag);
   void is(Object a, Object b, String name);
   void isnot(Object a, Object b, String name);
   void todo(boolean condition, String name, String diag);
   void todo_is(Object a, Object b, String name);
   void todo_isnot(Object a, Object b, String name);
   void info(String name, String message);
 }
--- a/build/mobile/robocop/Driver.java.in
+++ b/build/mobile/robocop/Driver.java.in
@@ -63,19 +63,9 @@ public interface Driver {
   int getHeight();
   int getGeckoTop();
   int getGeckoLeft();
   int getGeckoWidth();
   int getGeckoHeight();
 
   void startFrameRecording();
   int stopFrameRecording();
-  void dumpLog(String message);
-  void setLogFile(String filename);
-
-  void ok(boolean condition, String name, String diag);
-  void is(Object a, Object b, String name);
-  void isnot(Object a, Object b, String name);
-  void todo(boolean condition, String name, String diag);
-  void todo_is(Object a, Object b, String name);
-  void todo_isnot(Object a, Object b, String name);
-  void info(String name, String message);
 }
--- a/build/mobile/robocop/FennecNativeAssert.java.in
+++ b/build/mobile/robocop/FennecNativeAssert.java.in
@@ -44,16 +44,17 @@ import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Date;
 
 import java.lang.Class;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.InvocationHandler;
 import java.lang.Long;
 
@@ -72,17 +73,32 @@ public class FennecNativeAssert implemen
   
   // Objects for reflexive access of fennec classes.
 
   private LinkedList<testInfo> testList = new LinkedList<testInfo>();
 
   // If waiting for an event.
   private boolean asleep = false;
 
-  public FennecNativeAssert(){
+  // Internal state variables to make logging match up with existing mochitests
+  private int lineNumber = 0;
+  private int passed = 0;
+  private int failed = 0;
+  private int todo = 0;
+  
+  // Used to write the first line of the test file
+  private boolean logStarted = false;
+
+  // Used to write the test-start/test-end log lines
+  private String logTestName = "";
+
+  // Measure the time it takes to run test case
+  private long startTime = 0;
+
+  public FennecNativeAssert() {
   }
 
   // Write information to a logfile and logcat
   public void dumpLog(String message)
   {
     File file = new File(logFile);
     BufferedWriter bw = null;
 
@@ -105,66 +121,128 @@ public class FennecNativeAssert implemen
 
     Log.i("Robocop", message);
   }
 
   // Set the filename used for dumpLog.
   public void setLogFile(String filename)
   {
     logFile = filename;
+
+    //TODO: these two messages are mochitest specific
+    String message;
+    if (!logStarted) {
+      message = Integer.toString(lineNumber++) + " INFO SimpleTest START";
+      dumpLog(message);
+      logStarted = true;
+    }
+
+    if (logTestName != "") {
+      message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
+      long diff = (new Date().getTime()) - startTime;
+      message += " | finished in " + diff + "ms";
+      dumpLog(message);
+      logTestName = "";
+    }
   }
 
+  public void setTestName(String testName)
+  {
+    String[] nameParts = testName.split("\\.");
+    logTestName = nameParts[nameParts.length - 1];
+    startTime = new Date().getTime();
+
+    //TODO: this is mochitest specific
+    String message = Integer.toString(lineNumber++) + " INFO TEST-START | " + logTestName;
+    dumpLog(message);
+  }
 
   class testInfo {
     public boolean result;
     public String name;
     public String diag;
     public boolean todo;
     public testInfo(boolean r, String n, String d, boolean t) {
       result = r;
       name = n;
       diag = d;
       todo = t;
     }
 
   }
 
-
-  private void _logResult(testInfo test, String passString, String failString)
+  private void _logMochitestResult(testInfo test, String passString, String failString)
   {
     boolean isError = true;
     String resultString = failString;
-    if(test.result || test.todo){
+    if (test.result || test.todo) {
       isError = false;
     }
-    if(test.result)
+    if (test.result)
     {
       resultString = passString;
     }
-    String diag= test.name;
-    if(test.diag!=null) diag+= " - " + test.diag;
+    String diag = test.name;
+    if (test.diag != null) diag += " - " + test.diag;
 
-    String message = resultString + " | " + "ROBOCOP" + " | " + diag;
-    if(isError) {
-      if(logFile == null)
+    String message = Integer.toString(lineNumber++) + " INFO " + resultString + " | " + logTestName + " | " + diag;
+    if (isError) {
+      if (logFile == null)
       {
         assert(false);
       }
       else {
         dumpLog(message);
       }
     }
     else {
       dumpLog(message);
     }
+
+    if (test.todo) {
+      todo++;
+    } else if (isError) {
+      failed++;
+    } else {
+      passed++;
+    }
+  }
+
+  public void finalize()
+  {
+    // It appears that we call finalize during cleanup, this might be an invalid assertion.
+    String message;
+
+    if (logTestName != "") {
+      long diff = (new Date().getTime()) - startTime;
+
+      //TODO: this is mochitest specific
+      message = Integer.toString(lineNumber++) + " INFO TEST-END | " + logTestName;
+      message += " | finished in " + diff + "ms";
+      dumpLog(message);
+
+      logTestName = "";
+    }
+
+    //TODO: this is all mochitest specific
+    message = Integer.toString(lineNumber++) + " INFO TEST-START | Shutdown";
+    dumpLog(message);
+    message = Integer.toString(lineNumber++) + " INFO Passed: " + Integer.toString(passed);
+    dumpLog(message);
+    message = Integer.toString(lineNumber++) + " INFO Failed: " + Integer.toString(failed);
+    dumpLog(message);
+    message = Integer.toString(lineNumber++) + " INFO Todo: " + Integer.toString(todo);
+    dumpLog(message);
+    message = Integer.toString(lineNumber++) + " INFO SimpleTest FINISHED";
+    dumpLog(message);
   }
 
   public void ok(boolean condition, String name, String diag) {
     testInfo test = new testInfo(condition, name, diag, false);
-    _logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
+    _logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
     testList.add(test);
   }
 
   public void is(Object a, Object b, String name) {
     boolean pass = a.equals(b);
     String diag = "got " + a.toString() + ", expected " + b.toString();
     if(pass) {
       diag = a.toString() + " should equal " + b.toString();
@@ -178,17 +256,17 @@ public class FennecNativeAssert implemen
     if(pass) {
       diag = a.toString() + " should not equal " + b.toString();
     }
     ok(pass, name, diag);
   }
 
   public void todo(boolean condition, String name, String diag) {
     testInfo test = new testInfo(condition, name, diag, true);
-    _logResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
+    _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
     testList.add(test);
   }
 
   public void todo_is(Object a, Object b, String name) {
     boolean pass = a.equals(b);
     String diag = "got " + a.toString() + ", expected " + b.toString();
     if(pass) {
       diag = a.toString() + " should equal " + b.toString();
@@ -202,11 +280,11 @@ public class FennecNativeAssert implemen
     if(pass) {
       diag = a.toString() + " should not equal " + b.toString();
     }
     todo(pass, name, diag);
   }
 
   public void info(String name, String message) {
     testInfo test = new testInfo(true, name, message, false);
-    _logResult(test, "TEST-INFO", "INFO FAILED?");
+    _logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
   }
 }
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -65,32 +65,28 @@ import org.json.*;
 
 import com.jayway.android.robotium.solo.Solo;
 
 public class FennecNativeDriver implements Driver {
   // Map of IDs to element names.
   private HashMap locators = null;
   private Activity activity;
   private Solo solo;
-  private String logFile;
 
   // Objects for reflexive access of fennec classes.
   private ClassLoader classLoader;
   private Class gel;
   private Class ge;
   private Class gas;
   private Method registerGEL;
   private Method unregisterGEL;
   private Method sendGE;
   private Method _startFrameRecording;
   private Method _stopFrameRecording;
 
-
-  private LinkedList<testInfo> testList = new LinkedList<testInfo>();
-
   public FennecNativeDriver(Activity activity, Solo robocop){
     this.activity = activity;
     this.solo = robocop;
 
     // Set up table of fennec_ids.
     locators = convertTextToTable(getFile("/mnt/sdcard/fennec_ids.txt"));
 
     // Set up reflexive access of java classes and methods.
@@ -281,144 +277,21 @@ public class FennecNativeDriver implemen
         text.append('\n');
       }
     } catch(IOException e) {
       e.printStackTrace();
     }
     return text.toString();  
   }
 
-  // Write information to a logfile and logcat
-  public void dumpLog(String message)
-  {
-    File file = new File(logFile);
-    BufferedWriter bw = null;
-
-    try {
-      bw = new BufferedWriter(new FileWriter(logFile, true));
-      bw.write(message);
-      bw.newLine();
-    } catch(IOException e) {
-      e.printStackTrace();
-    } finally {
-      try {
-        if (bw != null) {
-          bw.flush();
-          bw.close();
-        }
-      } catch (IOException ex) {
-        ex.printStackTrace();
-      }
-    }
-
-    Log.i("Robocop", message);
-  }
-
-  // Set the filename used for dumpLog.
-  public void setLogFile(String filename)
-  {
-    logFile = filename;
-  }
-
   // Takes a string of "key=value" pairs split by \n and creates a hash table.
   public static HashMap convertTextToTable(String data)
   {
     HashMap retVal = new HashMap();
 
     String[] lines = data.split("\n");
     for (int i = 0; i < lines.length; i++) {
       String[] parts = lines[i].split("=");
       retVal.put(parts[0].trim(), parts[1].trim());
     }
     return retVal;
   }
-
-  class testInfo {
-    public boolean result;
-    public String name;
-    public String diag;
-    public boolean todo;
-    public testInfo(boolean r, String n, String d, boolean t) {
-      result = r;
-      name = n;
-      diag = d;
-      todo = t;
-    }
-
-  }
-
-
-  private void _logResult(testInfo test, String passString, String failString)
-  {
-    boolean isError = true;
-    String resultString = failString;
-    if(test.result || test.todo){
-      isError = false;
-    }
-    if(test.result)
-    {
-      resultString = passString;
-    }
-    String diag= test.name;
-    if(test.diag!=null) diag+= " - " + test.diag;
-
-    String message = resultString + " | " + "ROBOCOP" + " | " + diag;
-    if(isError) {
-      dumpLog(message);
-    }
-    else {
-      dumpLog(message);
-    }
-  }
-
-  public void ok(boolean condition, String name, String diag) {
-    testInfo test = new testInfo(condition, name, diag, false);
-    _logResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
-    testList.add(test);
-  }
-
-  public void is(Object a, Object b, String name) {
-    boolean pass = a.equals(b);
-    String diag = "got " + a.toString() + ", expected " + b.toString();
-    if(pass) {
-      diag = a.toString() + " should equal " + b.toString();
-    }
-    ok(pass, name, diag);
-  }
-  
-  public void isnot(Object a, Object b, String name) {
-    boolean pass = !a.equals(b);
-    String diag = "didn't expect " + a.toString() + ", but got it";
-    if(pass) {
-      diag = a.toString() + " should not equal " + b.toString();
-    }
-    ok(pass, name, diag);
-  }
-
-  public void todo(boolean condition, String name, String diag) {
-    testInfo test = new testInfo(condition, name, diag, true);
-    _logResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
-    testList.add(test);
-  }
-
-  public void todo_is(Object a, Object b, String name) {
-    boolean pass = a.equals(b);
-    String diag = "got " + a.toString() + ", expected " + b.toString();
-    if(pass) {
-      diag = a.toString() + " should equal " + b.toString();
-    }
-    todo(pass, name, diag);
-  }
-  
-  public void todo_isnot(Object a, Object b, String name) {
-    boolean pass = !a.equals(b);
-    String diag = "didn't expect " + a.toString() + ", but got it";
-    if(pass) {
-      diag = a.toString() + " should not equal " + b.toString();
-    }
-    todo(pass, name, diag);
-  }
-
-  public void info(String name, String message) {
-    testInfo test = new testInfo(true, name, message, false);
-    _logResult(test, "TEST-INFO", "INFO FAILED?");
-  }
 }
--- a/mobile/android/base/tests/BaseTest.java.in
+++ b/mobile/android/base/tests/BaseTest.java.in
@@ -46,25 +46,26 @@ abstract class BaseTest extends Activity
         // Start the activity
         setActivityIntent(i);
         mActivity = getActivity();
 
         // Set up Robotium.solo and Driver objects
         mSolo = new Solo(getInstrumentation());
         mDriver = new FennecNativeDriver(mActivity, mSolo);
         mActions = new FennecNativeActions(mActivity, mSolo, getInstrumentation());
-        mDriver.setLogFile((String)config.get("logfile"));
 
         mAsserter = new FennecNativeAssert();
         mAsserter.setLogFile((String)config.get("logfile"));
+        mAsserter.setTestName(this.getClass().getName());
     }
 
     @Override
     public void tearDown() throws Exception {
         try {
+            mAsserter.finalize();
             mSolo.finalize();
         } catch (Throwable e) {
             e.printStackTrace();
         }
         getActivity().finish();
         super.tearDown();
     }
 
--- a/mobile/android/base/tests/testPan.java.in
+++ b/mobile/android/base/tests/testPan.java.in
@@ -27,13 +27,13 @@ public class testPan extends BaseTest {
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             i++;
         } while (i < 1000 && mDriver.getScrollHeight() + 2 * mDriver.getHeight() < mDriver.getPageHeight());
         // asserter.ok(i < 1000, "Less than 1000", "Should take less than 1000 drags to get to bottom of the page.");
 
         int frames = mDriver.stopFrameRecording();
-        mDriver.dumpLog("__start_report" + Integer.toString(frames) + "__end_report");
+        mAsserter.dumpLog("__start_report" + Integer.toString(frames) + "__end_report");
         long msecs = System.currentTimeMillis();
-        mDriver.dumpLog("__startTimestamp" + msecs + "__endTimestamp");
+        mAsserter.dumpLog("__startTimestamp" + msecs + "__endTimestamp");
     }	
 }
--- a/testing/mochitest/runtestsremote.py
+++ b/testing/mochitest/runtestsremote.py
@@ -186,16 +186,17 @@ class RemoteOptions(MochitestOptions):
         options.httpPort = tempPort
 
         return options 
 
 class MochiRemote(Mochitest):
 
     _automation = None
     _dm = None
+    localProfile = None
 
     def __init__(self, automation, devmgr, options):
         self._automation = automation
         Mochitest.__init__(self, self._automation)
         self._dm = devmgr
         self.runSSLTunnel = False
         self.remoteProfile = options.remoteTestRoot + "/profile"
         self._automation.setRemoteProfile(self.remoteProfile)
@@ -273,16 +274,18 @@ class MochiRemote(Mochitest):
         options.xrePath = remoteXrePath
         options.utilityPath = remoteUtilityPath
         options.profilePath = remoteProfilePath
          
     def stopWebServer(self, options):
         self.server.stop()
         
     def buildProfile(self, options):
+        if self.localProfile:
+            options.profilePath = self.localProfile
         manifest = Mochitest.buildProfile(self, options)
         self.localProfile = options.profilePath
         self._dm.removeDir(self.remoteProfile)
         if self._dm.pushDir(options.profilePath, self.remoteProfile) == None:
             raise devicemanager.FileError("Unable to copy profile to device.")
 
         options.profilePath = self.remoteProfile
         return manifest
@@ -314,17 +317,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" or options.robocop):
+    if (options.dm_trans == "adb"):
         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)
@@ -346,55 +349,58 @@ 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)
+        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)
+        mp = manifestparser.TestManifest(strict=False)
+        # TODO: pull this in dynamically
+        mp.read('robocop.ini')
+        robocop_tests = mp.active_tests(exists=False)
 
-      fHandle = open("robotium.config", "w")
-      fHandle.write("profile=%s\n" % (mochitest.remoteProfile))
-      fHandle.write("logfile=%s\n" % (options.remoteLogFile))
-      fHandle.close()
-      deviceRoot = dm.getDeviceRoot()
+        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)
+        # 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")])
 
-      if (options.dm_trans == 'adb'):
-        dm.checkCmd(["install", "-r", os.path.join(options.robocop, "robocop.apk")])
+        appname = options.app
         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)
+            options.app = "am"
+            options.browserArgs = ["instrument", "-w", "-e", "class"]
+            options.browserArgs.append("%s.tests.%s" % (appname, test['name']))
+            options.browserArgs.append("org.mozilla.roboexample.test/android.test.InstrumentationTestRunner")
+
+            try:
+                retVal = mochitest.runTests(options)
+            except:
+                print "TEST-UNEXPECTED-ERROR | %s | Exception caught while running robocop tests." % sys.exc_info()[1]
+                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()