Java tutorial
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.tests; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.PowerManager; import android.test.ActivityInstrumentationTestCase2; import android.text.TextUtils; import android.util.Log; import com.jayway.android.robotium.solo.Solo; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.mozilla.gecko.Actions; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.Assert; import org.mozilla.gecko.BrowserApp; import org.mozilla.gecko.Driver; import org.mozilla.gecko.FennecInstrumentationTestRunner; import org.mozilla.gecko.FennecMochitestAssert; import org.mozilla.gecko.FennecNativeActions; import org.mozilla.gecko.FennecNativeDriver; import org.mozilla.gecko.FennecTalosAssert; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoEvent; import org.mozilla.gecko.updater.UpdateServiceHelper; import java.util.Map; @SuppressWarnings("unchecked") public abstract class BaseRobocopTest extends ActivityInstrumentationTestCase2<Activity> { public static final String LOGTAG = "BaseTest"; public enum Type { MOCHITEST, TALOS } public static final String DEFAULT_ROOT_PATH = "/mnt/sdcard/tests"; // How long to wait for a Robocop:Quit message to actually kill Fennec. private static final int ROBOCOP_QUIT_WAIT_MS = 180000; /** * The Java Class instance that launches the browser. * <p> * This should always agree with {@link AppConstants#MOZ_ANDROID_BROWSER_INTENT_CLASS}. */ public static final Class<? extends Activity> BROWSER_INTENT_CLASS; // Use reflection here so we don't have to preprocess this file. static { Class<? extends Activity> cl; try { cl = (Class<? extends Activity>) Class.forName(AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS); } catch (ClassNotFoundException e) { // Oh well. cl = Activity.class; } BROWSER_INTENT_CLASS = cl; } protected Assert mAsserter; protected String mLogFile; protected String mBaseHostnameUrl; protected String mBaseIpUrl; protected Map<String, String> mConfig; protected String mRootPath; protected Solo mSolo; protected Driver mDriver; protected Actions mActions; protected String mProfile; protected StringHelper mStringHelper; /** * The browser is started at the beginning of this test. A single test is a * class inheriting from <code>BaseRobocopTest</code> that contains test * methods. * <p> * If a test should not start the browser at the beginning of a test, * specify a different activity class to the one-argument constructor. To do * as little as possible, specify <code>Activity.class</code>. */ public BaseRobocopTest() { this((Class<Activity>) BROWSER_INTENT_CLASS); } /** * Start the given activity class at the beginning of this test. * <p> * <b>You should use the no-argument constructor in almost all cases.</b> * * @param activityClass to start before this test. */ protected BaseRobocopTest(Class<Activity> activityClass) { super(activityClass); } /** * Returns the test type: mochitest or talos. * <p> * By default tests are mochitests, but a test can override this method in * order to change its type. Most Robocop tests are mochitests. */ protected Type getTestType() { return Type.MOCHITEST; } // Member function to allow specialization. protected Intent createActivityIntent() { return BaseRobocopTest.createActivityIntent(mConfig); } // Static function to allow re-use. public static Intent createActivityIntent(Map<String, String> config) { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.putExtra("args", "-no-remote -profile " + config.get("profile")); // Don't show the first run experience. intent.putExtra(BrowserApp.EXTRA_SKIP_STARTPANE, true); final String envString = config.get("envvars"); if (!TextUtils.isEmpty(envString)) { final String[] envStrings = envString.split(","); for (int iter = 0; iter < envStrings.length; iter++) { intent.putExtra("env" + iter, envStrings[iter]); } } return intent; } @Override protected void setUp() throws Exception { // Disable the updater. UpdateServiceHelper.setEnabled(false); // Load config file from root path (set up by Python script). mRootPath = FennecInstrumentationTestRunner.getFennecArguments().getString("deviceroot"); if (mRootPath == null) { Log.w("Robocop", "Did not find deviceroot in arguments; falling back to: " + DEFAULT_ROOT_PATH); mRootPath = DEFAULT_ROOT_PATH; } String configFile = FennecNativeDriver.getFile(mRootPath + "/robotium.config"); mConfig = FennecNativeDriver.convertTextToTable(configFile); mLogFile = mConfig.get("logfile"); mProfile = mConfig.get("profile"); mBaseHostnameUrl = mConfig.get("host").replaceAll("(/$)", ""); mBaseIpUrl = mConfig.get("rawhost").replaceAll("(/$)", ""); // Initialize the asserter. if (getTestType() == Type.TALOS) { mAsserter = new FennecTalosAssert(); } else { mAsserter = new FennecMochitestAssert(); } mAsserter.setLogFile(mLogFile); mAsserter.setTestName(getClass().getName()); // Start the activity. final Intent intent = createActivityIntent(); setActivityIntent(intent); // Set up Robotium.solo and Driver objects Activity tempActivity = getActivity(); StringHelper.initialize(tempActivity.getResources()); mStringHelper = StringHelper.get(); mSolo = new Solo(getInstrumentation(), tempActivity); mDriver = new FennecNativeDriver(tempActivity, mSolo, mRootPath); mActions = new FennecNativeActions(tempActivity, mSolo, getInstrumentation(), mAsserter); } @Override public void tearDown() throws Exception { try { mAsserter.endTest(); // By default, we don't quit Fennec on finish, and we don't finish // all opened activities. Not quiting Fennec entirely is intended to // make life better for local testers, who might want to alter a // test that is under development rather than Fennec itself. Not // finishing activities is intended to allow local testers to // manually inspect an activity's state after a test // run. runtestsremote.py sets this to "1". Testers running via an // IDE will not have this set at all. final String quitAndFinish = FennecInstrumentationTestRunner.getFennecArguments() .getString("quit_and_finish"); // null means not specified. if ("1".equals(quitAndFinish)) { // Request the browser force quit and wait for it to take effect. Log.i(LOGTAG, "Requesting force quit."); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Robocop:Quit", null)); mSolo.sleep(ROBOCOP_QUIT_WAIT_MS); // If still running, finish activities as recommended by Robotium. Log.i(LOGTAG, "Finishing all opened activities."); mSolo.finishOpenedActivities(); } else { // This has the effect of keeping the activity-under-test // around; if we don't set it to null, it is killed, either by // finishOpenedActivities above or super.tearDown below. Log.i(LOGTAG, "Not requesting force quit and trying to keep started activity alive."); setActivity(null); } } catch (Throwable e) { e.printStackTrace(); } super.tearDown(); } /** * Function to early abort if we can't reach the given HTTP server. Provides local testers * with diagnostic information. Not currently available for TALOS tests, which are rarely run * locally in any case. */ public void throwIfHttpGetFails() { if (getTestType() == Type.TALOS) { return; } // rawURL to test fetching from. This should be a raw (IP) URL, not an alias // (like mochi.test). We can't (easily) test fetching from the aliases, since // those are managed by Fennec's proxy settings. final String rawUrl = ((String) mConfig.get("rawhost")).replaceAll("(/$)", ""); try { final HttpClient httpclient = new DefaultHttpClient(); final HttpResponse response = httpclient.execute(new HttpGet(rawUrl)); final int statusCode = response.getStatusLine().getStatusCode(); if (200 != statusCode) { throw new IllegalStateException("Status code: " + statusCode); } } catch (Exception e) { mAsserter.ok(false, "Robocop tests on your device need network/wifi access to reach: [" + rawUrl + "].", e.toString()); } } /** * Ensure that the screen on the test device is powered on during tests. */ public void throwIfScreenNotOn() { final PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE); mAsserter.ok(pm.isScreenOn(), "Robocop tests need the test device screen to be powered on.", ""); } }