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

Commit 40b97d46 authored by Tsu Chiang Chuang's avatar Tsu Chiang Chuang Committed by Android (Google) Code Review
Browse files

Merge "App Compatibility test. Launches a given app and detects crashes or ANRs."

parents 8c64376b fea39c37
Loading
Loading
Loading
Loading
+31 −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.

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests

# Include all test java files.
LOCAL_SRC_FILES := \
	$(call all-java-files-under, src)


LOCAL_SDK_VERSION := 8
LOCAL_PACKAGE_NAME := AppCompatibilityTest

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))
+29 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.compatibilitytest" >
    <application >
        <uses-library android:name="android.test.runner" />
    </application>

    <instrumentation
        android:name=".AppCompatibilityRunner"
        android:targetPackage="com.android.compatibilitytest"
        android:label="App Compability Test Runner" />

    <uses-sdk android:minSdkVersion="8"></uses-sdk>
</manifest>
+165 −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.compatibilitytest;

import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.test.InstrumentationTestCase;
import android.util.Log;

import junit.framework.Assert;

import java.util.Collection;

/**
 * Application Compatibility Test that launches an application and detects crashes.
 */
public class AppCompatibility extends InstrumentationTestCase {

    private static final String TAG = "AppCompability";
    private static final String PACKAGE_TO_LAUNCH = "package_to_launch";
    private static final String APP_LAUNCH_TIMEOUT_MSECS = "app_launch_timeout_ms";
    private static final String WORKSPACE_LAUNCH_TIMEOUT_MSECS = "workspace_launch_timeout_ms";

    private int mAppLaunchTimeout = 7000;
    private int mWorkspaceLaunchTimeout = 2000;

    private Context mContext;
    private ActivityManager mActivityManager;
    private PackageManager mPackageManager;
    private AppCompatibilityRunner mRunner;
    private Bundle mArgs;

    @Override
    public void setUp() throws Exception{
        super.setUp();
        mRunner = (AppCompatibilityRunner) getInstrumentation();
        assertNotNull("Could not fetch InstrumentationTestRunner.",mRunner);

        mContext = mRunner.getTargetContext();
        Assert.assertNotNull("Could not get the Context", mContext);

        mActivityManager = (ActivityManager)
                mContext.getSystemService(Context.ACTIVITY_SERVICE);
        Assert.assertNotNull("Could not get Activity Manager", mActivityManager);

        mPackageManager = mContext.getPackageManager();
        Assert.assertNotNull("Missing Package Manager", mPackageManager);

        mArgs = mRunner.getBundle();

        // Parse optional inputs.
        String appLaunchTimeoutMsecs = mArgs.getString(APP_LAUNCH_TIMEOUT_MSECS);
        if (appLaunchTimeoutMsecs != null) {
            mAppLaunchTimeout = Integer.parseInt(appLaunchTimeoutMsecs);
        }
        String workspaceLaunchTimeoutMsecs = mArgs.getString(WORKSPACE_LAUNCH_TIMEOUT_MSECS);
        if (workspaceLaunchTimeoutMsecs != null) {
            mWorkspaceLaunchTimeout = Integer.parseInt(workspaceLaunchTimeoutMsecs);
        }
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    /**
     * Actual test case that launches the package and throws an exception on the first error.
     * @throws Exception
     */
    public void testAppStability() throws Exception {
        String packageName = mArgs.getString(PACKAGE_TO_LAUNCH);
        if (packageName != null) {
            Log.d(TAG, "Launching app " + packageName);
            Collection<ProcessErrorStateInfo> err = launchActivity(packageName);
            // Make sure there are no errors when launching the application, otherwise raise an
            // exception with the first error encountered.
            assertNull(getFirstError(err), err);
        } else {
            Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH +
                    " to specify the package to launch");
        }
    }

    /**
     * Gets the first error in collection and return the long message for it.
     * @param in {@link Collection} of {@link ProcessErrorStateInfo} to parse.
     * @return {@link String} the long message of the error.
     */
    private String getFirstError(Collection<ProcessErrorStateInfo> in) {
        if (in == null) {
            return null;
        }
        ProcessErrorStateInfo err = in.iterator().next();
        if (err != null) {
            return err.stackTrace;
        }
        return null;
    }

    /**
     * Launches and activity and queries for errors.
     * @param packageName {@link String} the package name of the application to launch.
     * @return  {@link Collection} of {@link ProcessErrorStateInfo} detected during the app launch.
     */
    private Collection<ProcessErrorStateInfo> launchActivity(String packageName) {
        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
        homeIntent.addCategory(Intent.CATEGORY_HOME);
        homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        Intent intent = mPackageManager.getLaunchIntentForPackage(packageName);

        // We check for any Crash or ANR dialogs that are already up, and we ignore them.  This is
        // so that we don't report crashes that were caused by prior apps (which those particular
        // tests should have caught and reported already).  Otherwise, test failures would cascade
        // from the initial broken app to many/all of the tests following that app's launch.
        final Collection<ProcessErrorStateInfo> preErr = mActivityManager.getProcessesInErrorState();

        // Launch Activity
        mContext.startActivity(intent);

        try {
            Thread.sleep(mAppLaunchTimeout);
        } catch (InterruptedException e) {
            // ignore
        }

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

        // See if there are any errors.  We wait until down here to give ANRs as much time as
        // possible to occur.
        final Collection<ProcessErrorStateInfo> postErr =
                mActivityManager.getProcessesInErrorState();
        // Take the difference between the error processes we see now, and the ones that were
        // present when we started
        if (preErr != null && postErr != null) {
            postErr.removeAll(preErr);
        }
        return postErr;
    }
}
+35 −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.compatibilitytest;

import android.os.Bundle;
import android.test.InstrumentationTestRunner;

public class AppCompatibilityRunner extends InstrumentationTestRunner {

    private Bundle mArgs;

    @Override
    public void onCreate(Bundle args) {
        super.onCreate(args);
        mArgs = args;
    }

    public Bundle getBundle() {
        return mArgs;
    }
}