Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d441a1c authored by Omari Stephens's avatar Omari Stephens Committed by Android (Google) Code Review
Browse files

Merge "Refactor smoke tests to enable one-app-per-testcase runs"

parents 34ba5a0a 5ae3dfe5
Loading
Loading
Loading
Loading
+16 −6
Original line number Diff line number Diff line
@@ -18,20 +18,30 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.smoketest.tests">

    <!-- We add an application tag here just so that we can indicate that
         this package needs to link against the android.test library,
         which is needed when building test cases. -->    
    <!--
    We add an application tag here just so that we can indicate that this package needs to link
    against the android.test library, which is needed when building test cases.
    -->
    <application>
        <uses-library android:name="android.test.runner" />
    </application>

    <!--
    This declares that this app uses the instrumentation test runner targeting
    the package of com.android.smoketest.  To run the tests use the command:
    "adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner"
    This declares that this app uses the instrumentation test runner targeting the package of
    com.android.smoketest.  To run the tests use the command:
    `adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner`
    -->
    <instrumentation android:name="android.test.InstrumentationTestRunner"
                     android:targetPackage="com.android.smoketest"
                     android:label="System Smoke Tests"/>

    <!--
    This declares a method to run the instrumentation with a special runner, which will run each
    app as a separate testcase.  To do so, use the command:
    `adb shell am instrument -w com.android.smoketest.tests/com.android.smoketest.SmokeTestRunner`
    -->
    <instrumentation android:name="com.android.smoketest.SmokeTestRunner"
                     android:targetPackage="com.android.smoketest"
                     android:label="System Smoke Tests"/>

</manifest>
+83 −47
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package com.android.smoketest;

import com.android.internal.os.RuntimeInit;

import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
@@ -43,9 +41,17 @@ public class ProcessErrorsTest extends AndroidTestCase {
    
    private static final String TAG = "ProcessErrorsTest";

    private final Intent mHomeIntent;

    protected ActivityManager mActivityManager;
    protected PackageManager mPackageManager;

    public ProcessErrorsTest() {
        mHomeIntent = new Intent(Intent.ACTION_MAIN);
        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
@@ -59,7 +65,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
        assertNotNull(mPackageManager);
    }

    public void testNoProcessErrors() throws Exception {
    public void testNoProcessErrorsAfterBoot() throws Exception {
        final String reportMsg = checkForProcessErrors();
        if (reportMsg != null) {
            Log.w(TAG, reportMsg);
@@ -82,54 +88,84 @@ public class ProcessErrorsTest extends AndroidTestCase {
    }

    /**
     * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
     * happened while doing so.
     * <p />
     * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the
     * FIXME: first app doesn't go away.
     * A helper function to query the provided {@link PackageManager} for a list of Activities that
     * can be launched from Launcher.
     */
    public void testRunAllActivities() throws Exception {
        final Intent home = new Intent(Intent.ACTION_MAIN);
        home.addCategory(Intent.CATEGORY_HOME);
        home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    static List<ResolveInfo> getLauncherActivities(PackageManager pm) {
        final Intent launchable = new Intent(Intent.ACTION_MAIN);
        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
        final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
        final Set<ProcessError> errSet = new HashSet<ProcessError>();

        for (ResolveInfo info : activities) {
            Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
                    info.activityInfo.name));
        final List<ResolveInfo> activities = pm.queryIntentActivities(launchable, 0);
        return activities;
    }

            // build an Intent to launch the app
            final ComponentName component = new ComponentName(info.activityInfo.packageName,
                    info.activityInfo.name);
    /**
     * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying
     * an activity to be launched.
     */
    static Intent intentForActivity(ResolveInfo app) {
        // build an Intent to launch the specified app
        final ComponentName component = new ComponentName(app.activityInfo.packageName,
                app.activityInfo.name);
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setComponent(component);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        return intent;
    }

    /**
     * A method to run the specified Activity and return a {@link Collection} of the Activities that
     * were in an error state, as listed by {@link ActivityManager.getProcessesInErrorState()}.
     * <p />
     * The method will launch the app, wait for 7 seconds, check for apps in the error state, send
     * the Home intent, wait for 2 seconds, and then return.
     */
    public Collection<ProcessErrorStateInfo> runOneActivity(ResolveInfo app) {
        final long appLaunchWait = 7000;
        final long homeLaunchWait = 2000;

        Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName,
                app.activityInfo.name));

        // launch app, and wait 7 seconds for it to start/settle
        final Intent intent = intentForActivity(app);
        getContext().startActivity(intent);
        try {
                Thread.sleep(7000);
            Thread.sleep(appLaunchWait);
        } catch (InterruptedException e) {
            // ignore
        }

        // See if there are any errors
            Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
            if (procs != null) {
                errSet.addAll(ProcessError.fromCollection(procs));
            }
        final Collection<ProcessErrorStateInfo> errProcs =
                mActivityManager.getProcessesInErrorState();

        // Send the "home" intent and wait 2 seconds for us to get there
            getContext().startActivity(home);
        getContext().startActivity(mHomeIntent);
        try {
                Thread.sleep(2000);
            Thread.sleep(homeLaunchWait);
        } catch (InterruptedException e) {
            // ignore
        }

        return errProcs;
    }

    /**
     * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
     * happened while doing so.
     * <p />
     * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the
     * FIXME: first app doesn't go away.
     */
    public void testRunAllActivities() throws Exception {
        final Set<ProcessError> errSet = new HashSet<ProcessError>();

        for (ResolveInfo app : getLauncherActivities(mPackageManager)) {
            final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
            if (errProcs != null) {
                errSet.addAll(ProcessError.fromCollection(errProcs));
            }
        }

        if (!errSet.isEmpty()) {
@@ -138,7 +174,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
        }
    }

    private String reportWrappedListContents(Collection<ProcessError> errList) {
    String reportWrappedListContents(Collection<ProcessError> errList) {
        List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
        for (ProcessError err : errList) {
            newList.add(err.info);
@@ -186,7 +222,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
     * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
     * crashes are considered equal).
     */
    private static class ProcessError {
    static class ProcessError {
        public final ProcessErrorStateInfo info;

        public ProcessError(ProcessErrorStateInfo newInfo) {
+94 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.smoketest;

import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.test.InstrumentationTestRunner;

import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A special test runner which does a test-start for each app in a separate testcase
 */
public class SmokeTestRunner extends InstrumentationTestRunner {

    private static final String SUITE_NAME = "Smoke Test Suite";

    /**
     * Returns a single testcase for each app to launch
     */
    @Override
    public TestSuite getAllTests() {
        final TestSuite suite = new TestSuite(SUITE_NAME);

        final PackageManager pm = getTargetContext().getPackageManager();
        final List<ResolveInfo> apps = ProcessErrorsTest.getLauncherActivities(pm);

        // FIXME: figure out some way to control the reported class names for these anonymous
        // FIXME: class instances.

        final TestCase setupTest = new ProcessErrorsTest() {
            @Override
            public void runTest() throws Exception {
                testSetUpConditions();
            }
        };
        setupTest.setName("testSetUpConditions");
        suite.addTest(setupTest);

        final TestCase postBootTest = new ProcessErrorsTest() {
            @Override
            public void runTest() throws Exception {
                testNoProcessErrorsAfterBoot();
            }
        };
        postBootTest.setName("testNoProcessErrorsAfterBoot");
        suite.addTest(postBootTest);

        for (final ResolveInfo app : apps) {
            final TestCase appTest = new ProcessErrorsTest() {
                @Override
                public void runTest() throws Exception {
                    final Set<ProcessError> errSet = new HashSet<ProcessError>();
                    final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
                    if (errProcs != null) {
                        errSet.addAll(ProcessError.fromCollection(errProcs));
                    }

                    if (!errSet.isEmpty()) {
                        fail(String.format("Got %d errors: %s", errSet.size(),
                                reportWrappedListContents(errSet)));
                    }
                }
            };
            appTest.setName(app.activityInfo.name);
            suite.addTest(appTest);
        }

        return suite;
    }
}