blob: b2a8847039c7cdab64ac2a310fae22b707faf048 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.test;
18
Fangqiu Su4c35c952023-12-19 18:14:19 +000019import static android.test.suitebuilder.TestPredicates.hasAnnotation;
Jack Wangff1df692009-08-26 17:19:13 -070020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.Activity;
22import android.app.Instrumentation;
23import android.os.Bundle;
24import android.os.Debug;
25import android.os.Looper;
26import android.test.suitebuilder.TestMethod;
27import android.test.suitebuilder.TestPredicates;
28import android.test.suitebuilder.TestSuiteBuilder;
Doug Zongker0375fa12010-02-23 12:36:06 -080029import android.test.suitebuilder.annotation.LargeTest;
Fangqiu Su4c35c952023-12-19 18:14:19 +000030import android.test.suitebuilder.annotation.MediumTest;
31import android.test.suitebuilder.annotation.SmallTest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.util.Log;
33
Fangqiu Su4c35c952023-12-19 18:14:19 +000034import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035
36import junit.framework.AssertionFailedError;
37import junit.framework.Test;
38import junit.framework.TestCase;
39import junit.framework.TestListener;
40import junit.framework.TestResult;
41import junit.framework.TestSuite;
42import junit.runner.BaseTestRunner;
43import junit.textui.ResultPrinter;
44
Fangqiu Su4c35c952023-12-19 18:14:19 +000045import java.io.ByteArrayOutputStream;
46import java.io.File;
47import java.io.PrintStream;
48import java.lang.annotation.Annotation;
49import java.lang.reflect.InvocationTargetException;
50import java.lang.reflect.Method;
51import java.util.ArrayList;
52import java.util.List;
Paul Duffinfedb4b72017-06-22 10:47:25 +010053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054/**
55 * An {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080056 * an Android package (application).
57 *
58 * <div class="special reference">
59 * <h3>Developer Guides</h3>
60 * <p>For more information about application testing, read the
61 * <a href="{@docRoot}guide/topics/testing/index.html">Testing</a> developer guide.</p>
62 * </div>
63 *
64 * <h3>Typical Usage</h3>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 * <ol>
66 * <li>Write {@link junit.framework.TestCase}s that perform unit, functional, or performance tests
67 * against the classes in your package. Typically these are subclassed from:
Jack Wangff1df692009-08-26 17:19:13 -070068 * <ul><li>{@link android.test.ActivityInstrumentationTestCase2}</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 * <li>{@link android.test.ActivityUnitTestCase}</li>
70 * <li>{@link android.test.AndroidTestCase}</li>
71 * <li>{@link android.test.ApplicationTestCase}</li>
72 * <li>{@link android.test.InstrumentationTestCase}</li>
73 * <li>{@link android.test.ProviderTestCase}</li>
74 * <li>{@link android.test.ServiceTestCase}</li>
75 * <li>{@link android.test.SingleLaunchActivityTestCase}</li></ul>
quddusce8df6f42014-01-06 16:28:03 -080076 * <li>Set the <code>android:targetPackage</code> attribute of the <code>&lt;instrumentation&gt;</code>
77 * element in the test package's manifest. You should set the attribute value
78 * to the package name of the target application under test.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * <li>Run the instrumentation using "adb shell am instrument -w",
80 * with no optional arguments, to run all tests (except performance tests).
81 * <li>Run the instrumentation using "adb shell am instrument -w",
82 * with the argument '-e func true' to run all functional tests. These are tests that derive from
83 * {@link android.test.InstrumentationTestCase}.
84 * <li>Run the instrumentation using "adb shell am instrument -w",
85 * with the argument '-e unit true' to run all unit tests. These are tests that <i>do not</i>derive
86 * from {@link android.test.InstrumentationTestCase} (and are not performance tests).
87 * <li>Run the instrumentation using "adb shell am instrument -w",
88 * with the argument '-e class' set to run an individual {@link junit.framework.TestCase}.
89 * </ol>
90 * <p/>
91 * <b>Running all tests:</b> adb shell am instrument -w
92 * com.android.foo/android.test.InstrumentationTestRunner
93 * <p/>
94 * <b>Running all small tests:</b> adb shell am instrument -w
95 * -e size small
96 * com.android.foo/android.test.InstrumentationTestRunner
97 * <p/>
98 * <b>Running all medium tests:</b> adb shell am instrument -w
99 * -e size medium
100 * com.android.foo/android.test.InstrumentationTestRunner
101 * <p/>
102 * <b>Running all large tests:</b> adb shell am instrument -w
103 * -e size large
104 * com.android.foo/android.test.InstrumentationTestRunner
105 * <p/>
Brett Chabot88e03a92010-02-19 09:57:11 -0800106 * <b>Filter test run to tests with given annotation:</b> adb shell am instrument -w
107 * -e annotation com.android.foo.MyAnnotation
108 * com.android.foo/android.test.InstrumentationTestRunner
109 * <p/>
110 * If used with other options, the resulting test run will contain the union of the two options.
111 * e.g. "-e size large -e annotation com.android.foo.MyAnnotation" will run only tests with both
112 * the {@link LargeTest} and "com.android.foo.MyAnnotation" annotations.
113 * <p/>
114 * <b>Filter test run to tests <i>without</i> given annotation:</b> adb shell am instrument -w
115 * -e notAnnotation com.android.foo.MyAnnotation
116 * com.android.foo/android.test.InstrumentationTestRunner
117 * <p/>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 * <b>Running a single testcase:</b> adb shell am instrument -w
119 * -e class com.android.foo.FooTest
120 * com.android.foo/android.test.InstrumentationTestRunner
121 * <p/>
122 * <b>Running a single test:</b> adb shell am instrument -w
123 * -e class com.android.foo.FooTest#testFoo
124 * com.android.foo/android.test.InstrumentationTestRunner
125 * <p/>
126 * <b>Running multiple tests:</b> adb shell am instrument -w
127 * -e class com.android.foo.FooTest,com.android.foo.TooTest
128 * com.android.foo/android.test.InstrumentationTestRunner
129 * <p/>
Brett Chabot89c0ef42010-03-18 20:03:31 -0700130 * <b>Running all tests in a java package:</b> adb shell am instrument -w
131 * -e package com.android.foo.subpkg
132 * com.android.foo/android.test.InstrumentationTestRunner
133 * <p/>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 * <b>Including performance tests:</b> adb shell am instrument -w
135 * -e perf true
136 * com.android.foo/android.test.InstrumentationTestRunner
137 * <p/>
138 * <b>To debug your tests, set a break point in your code and pass:</b>
139 * -e debug true
140 * <p/>
141 * <b>To run in 'log only' mode</b>
142 * -e log true
Jack Wangff1df692009-08-26 17:19:13 -0700143 * This option will load and iterate through all test classes and methods, but will bypass actual
144 * test execution. Useful for quickly obtaining info on the tests to be executed by an
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 * instrumentation command.
146 * <p/>
147 * <b>To generate EMMA code coverage:</b>
148 * -e coverage true
Jack Wangff1df692009-08-26 17:19:13 -0700149 * Note: this requires an emma instrumented build. By default, the code coverage results file
Brett Chabot51e03642009-05-28 18:18:15 -0700150 * will be saved in a /data/<app>/coverage.ec file, unless overridden by coverageFile flag (see
151 * below)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 * <p/>
153 * <b> To specify EMMA code coverage results file path:</b>
154 * -e coverageFile /sdcard/myFile.ec
155 * <br/>
156 * in addition to the other arguments.
Stephan Linznerb51617f2016-01-27 18:09:50 -0800157 * @deprecated Use
158 * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
159 * AndroidJUnitRunner</a> instead. New tests should be written using the
160 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 */
162
163/* (not JavaDoc)
164 * Although not necessary in most case, another way to use this class is to extend it and have the
Jack Wangff1df692009-08-26 17:19:13 -0700165 * derived class return the desired test suite from the {@link #getTestSuite()} method. The test
166 * suite returned from this method will be used if no target class is defined in the meta-data or
167 * command line argument parameters. If a derived class is used it needs to be added as an
168 * instrumentation to the AndroidManifest.xml and the command to run it would look like:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 * <p/>
170 * adb shell am instrument -w com.android.foo/<i>com.android.FooInstrumentationTestRunner</i>
171 * <p/>
172 * Where <i>com.android.FooInstrumentationTestRunner</i> is the derived class.
173 *
174 * This model is used by many existing app tests, but can probably be deprecated.
175 */
Stephan Linznerb51617f2016-01-27 18:09:50 -0800176@Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
178
179 /** @hide */
Paul Duffin575f9da2017-06-20 14:41:20 +0100180 static final String ARGUMENT_TEST_CLASS = "class";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 /** @hide */
Paul Duffin575f9da2017-06-20 14:41:20 +0100182 private static final String ARGUMENT_TEST_PACKAGE = "package";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 /** @hide */
Paul Duffin575f9da2017-06-20 14:41:20 +0100184 private static final String ARGUMENT_TEST_SIZE_PREDICATE = "size";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 /** @hide */
Paul Duffin575f9da2017-06-20 14:41:20 +0100186 static final String ARGUMENT_DELAY_MSEC = "delay_msec";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
188 private static final String SMALL_SUITE = "small";
Jack Wangff1df692009-08-26 17:19:13 -0700189 private static final String MEDIUM_SUITE = "medium";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private static final String LARGE_SUITE = "large";
Jack Wangff1df692009-08-26 17:19:13 -0700191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 private static final String ARGUMENT_LOG_ONLY = "log";
Brett Chabot88e03a92010-02-19 09:57:11 -0800193 /** @hide */
194 static final String ARGUMENT_ANNOTATION = "annotation";
195 /** @hide */
196 static final String ARGUMENT_NOT_ANNOTATION = "notAnnotation";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
Paul Duffinfedb4b72017-06-22 10:47:25 +0100198 private static final Predicate<TestMethod> SELECT_SMALL = hasAnnotation(SmallTest.class);
199
200 private static final Predicate<TestMethod> SELECT_MEDIUM = hasAnnotation(MediumTest.class);
201
202 private static final Predicate<TestMethod> SELECT_LARGE = hasAnnotation(LargeTest.class);
203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 /**
Jack Wangff1df692009-08-26 17:19:13 -0700205 * This constant defines the maximum allowed runtime (in ms) for a test included in the "small"
206 * suite. It is used to make an educated guess at what suite an unlabeled test belongs.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 */
208 private static final float SMALL_SUITE_MAX_RUNTIME = 100;
Jack Wangff1df692009-08-26 17:19:13 -0700209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 /**
Jack Wangff1df692009-08-26 17:19:13 -0700211 * This constant defines the maximum allowed runtime (in ms) for a test included in the
212 * "medium" suite. It is used to make an educated guess at what suite an unlabeled test belongs.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 */
214 private static final float MEDIUM_SUITE_MAX_RUNTIME = 1000;
Jack Wangff1df692009-08-26 17:19:13 -0700215
Paul Duffin575f9da2017-06-20 14:41:20 +0100216 /*
Jack Wangff1df692009-08-26 17:19:13 -0700217 * The following keys are used in the status bundle to provide structured reports to
218 * an IInstrumentationWatcher.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 */
220
221 /**
Jack Wangff1df692009-08-26 17:19:13 -0700222 * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 * identifies InstrumentationTestRunner as the source of the report. This is sent with all
224 * status messages.
225 */
226 public static final String REPORT_VALUE_ID = "InstrumentationTestRunner";
227 /**
Jack Wangff1df692009-08-26 17:19:13 -0700228 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 * identifies the total number of tests that are being run. This is sent with all status
230 * messages.
231 */
232 public static final String REPORT_KEY_NUM_TOTAL = "numtests";
233 /**
Jack Wangff1df692009-08-26 17:19:13 -0700234 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 * identifies the sequence number of the current test. This is sent with any status message
236 * describing a specific test being started or completed.
237 */
238 public static final String REPORT_KEY_NUM_CURRENT = "current";
239 /**
Jack Wangff1df692009-08-26 17:19:13 -0700240 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 * identifies the name of the current test class. This is sent with any status message
242 * describing a specific test being started or completed.
243 */
244 public static final String REPORT_KEY_NAME_CLASS = "class";
245 /**
Jack Wangff1df692009-08-26 17:19:13 -0700246 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 * identifies the name of the current test. This is sent with any status message
248 * describing a specific test being started or completed.
249 */
250 public static final String REPORT_KEY_NAME_TEST = "test";
251 /**
Jack Wangff1df692009-08-26 17:19:13 -0700252 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 * reports the run time in seconds of the current test.
254 */
255 private static final String REPORT_KEY_RUN_TIME = "runtime";
256 /**
Jack Wangff1df692009-08-26 17:19:13 -0700257 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
Jack Wang3fc03e62010-10-19 15:13:07 -0700258 * reports the number of total iterations of the current test.
259 */
260 private static final String REPORT_KEY_NUM_ITERATIONS = "numiterations";
261 /**
262 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 * reports the guessed suite assignment for the current test.
264 */
265 private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment";
266 /**
Brett Chabot51e03642009-05-28 18:18:15 -0700267 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
268 * identifies the path to the generated code coverage file.
269 */
270 private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
Jack Wangff1df692009-08-26 17:19:13 -0700271
272 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 * The test is starting.
274 */
275 public static final int REPORT_VALUE_RESULT_START = 1;
276 /**
277 * The test completed successfully.
278 */
279 public static final int REPORT_VALUE_RESULT_OK = 0;
280 /**
281 * The test completed with an error.
282 */
283 public static final int REPORT_VALUE_RESULT_ERROR = -1;
284 /**
285 * The test completed with a failure.
286 */
287 public static final int REPORT_VALUE_RESULT_FAILURE = -2;
288 /**
Jack Wangff1df692009-08-26 17:19:13 -0700289 * If included in the status bundle sent to an IInstrumentationWatcher, this key
290 * identifies a stack trace describing an error or failure. This is sent with any status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 * message describing a specific test being completed.
292 */
293 public static final String REPORT_KEY_STACK = "stack";
294
Brett Chabot51e03642009-05-28 18:18:15 -0700295 // Default file name for code coverage
296 private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec";
Jack Wangff1df692009-08-26 17:19:13 -0700297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 private static final String LOG_TAG = "InstrumentationTestRunner";
299
300 private final Bundle mResults = new Bundle();
David Hucbc584d2011-09-16 18:08:35 -0700301 private Bundle mArguments;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 private AndroidTestRunner mTestRunner;
303 private boolean mDebug;
304 private boolean mJustCount;
305 private boolean mSuiteAssignmentMode;
306 private int mTestCount;
307 private String mPackageOfTests;
308 private boolean mCoverage;
309 private String mCoverageFilePath;
310 private int mDelayMsec;
311
312 @Override
313 public void onCreate(Bundle arguments) {
314 super.onCreate(arguments);
David Hucbc584d2011-09-16 18:08:35 -0700315 mArguments = arguments;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316
317 // Apk paths used to search for test classes when using TestSuiteBuilders.
318 String[] apkPaths =
319 {getTargetContext().getPackageCodePath(), getContext().getPackageCodePath()};
320 ClassPathPackageInfoSource.setApkPaths(apkPaths);
321
322 Predicate<TestMethod> testSizePredicate = null;
Brett Chabot88e03a92010-02-19 09:57:11 -0800323 Predicate<TestMethod> testAnnotationPredicate = null;
324 Predicate<TestMethod> testNotAnnotationPredicate = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 String testClassesArg = null;
326 boolean logOnly = false;
327
328 if (arguments != null) {
329 // Test class name passed as an argument should override any meta-data declaration.
330 testClassesArg = arguments.getString(ARGUMENT_TEST_CLASS);
331 mDebug = getBooleanArgument(arguments, "debug");
332 mJustCount = getBooleanArgument(arguments, "count");
333 mSuiteAssignmentMode = getBooleanArgument(arguments, "suiteAssignment");
334 mPackageOfTests = arguments.getString(ARGUMENT_TEST_PACKAGE);
335 testSizePredicate = getSizePredicateFromArg(
336 arguments.getString(ARGUMENT_TEST_SIZE_PREDICATE));
Brett Chabot88e03a92010-02-19 09:57:11 -0800337 testAnnotationPredicate = getAnnotationPredicate(
338 arguments.getString(ARGUMENT_ANNOTATION));
339 testNotAnnotationPredicate = getNotAnnotationPredicate(
340 arguments.getString(ARGUMENT_NOT_ANNOTATION));
341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY);
343 mCoverage = getBooleanArgument(arguments, "coverage");
344 mCoverageFilePath = arguments.getString("coverageFile");
345
346 try {
347 Object delay = arguments.get(ARGUMENT_DELAY_MSEC); // Accept either string or int
348 if (delay != null) mDelayMsec = Integer.parseInt(delay.toString());
349 } catch (NumberFormatException e) {
350 Log.e(LOG_TAG, "Invalid delay_msec parameter", e);
351 }
352 }
353
354 TestSuiteBuilder testSuiteBuilder = new TestSuiteBuilder(getClass().getName(),
355 getTargetContext().getClassLoader());
356
357 if (testSizePredicate != null) {
358 testSuiteBuilder.addRequirements(testSizePredicate);
359 }
Brett Chabot88e03a92010-02-19 09:57:11 -0800360 if (testAnnotationPredicate != null) {
361 testSuiteBuilder.addRequirements(testAnnotationPredicate);
362 }
363 if (testNotAnnotationPredicate != null) {
364 testSuiteBuilder.addRequirements(testNotAnnotationPredicate);
365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366
367 if (testClassesArg == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 if (mPackageOfTests != null) {
369 testSuiteBuilder.includePackages(mPackageOfTests);
370 } else {
Brett Chabot61b10ac2009-03-31 17:04:34 -0700371 TestSuite testSuite = getTestSuite();
372 if (testSuite != null) {
373 testSuiteBuilder.addTestSuite(testSuite);
374 } else {
Jack Wangff1df692009-08-26 17:19:13 -0700375 // no package or class bundle arguments were supplied, and no test suite
Brett Chabot61b10ac2009-03-31 17:04:34 -0700376 // provided so add all tests in application
377 testSuiteBuilder.includePackages("");
378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380 } else {
381 parseTestClasses(testClassesArg, testSuiteBuilder);
382 }
Jack Wangff1df692009-08-26 17:19:13 -0700383
Urs Grobda13ef52009-04-17 11:30:14 -0700384 testSuiteBuilder.addRequirements(getBuilderRequirements());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385
386 mTestRunner = getAndroidTestRunner();
387 mTestRunner.setContext(getTargetContext());
Jack Wang7aba54b2009-08-20 19:20:54 -0700388 mTestRunner.setInstrumentation(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 mTestRunner.setSkipExecution(logOnly);
390 mTestRunner.setTest(testSuiteBuilder.build());
391 mTestCount = mTestRunner.getTestCases().size();
392 if (mSuiteAssignmentMode) {
393 mTestRunner.addTestListener(new SuiteAssignmentPrinter());
394 } else {
Jack Wangff1df692009-08-26 17:19:13 -0700395 WatcherResultPrinter resultPrinter = new WatcherResultPrinter(mTestCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 mTestRunner.addTestListener(new TestPrinter("TestRunner", false));
Jack Wangff1df692009-08-26 17:19:13 -0700397 mTestRunner.addTestListener(resultPrinter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 }
399 start();
400 }
401
David Hucbc584d2011-09-16 18:08:35 -0700402 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800403 * Get the arguments passed to this instrumentation.
David Hucbc584d2011-09-16 18:08:35 -0700404 *
405 * @return the Bundle object
David Hucbc584d2011-09-16 18:08:35 -0700406 */
Svetoslav3a34d172013-01-28 19:55:35 -0800407 public Bundle getArguments() {
David Hucbc584d2011-09-16 18:08:35 -0700408 return mArguments;
409 }
410
David Hu8cc9a8e2011-12-13 15:57:42 -0800411 /**
412 * Add a {@link TestListener}
David Hu8cc9a8e2011-12-13 15:57:42 -0800413 */
414 protected void addTestListener(TestListener listener){
415 if(mTestRunner!=null && listener!=null){
416 mTestRunner.addTestListener(listener);
417 }
418 }
419
Urs Grobda13ef52009-04-17 11:30:14 -0700420 List<Predicate<TestMethod>> getBuilderRequirements() {
421 return new ArrayList<Predicate<TestMethod>>();
422 }
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 /**
Jack Wangff1df692009-08-26 17:19:13 -0700425 * Parses and loads the specified set of test classes
426 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 * @param testClassArg - comma-separated list of test classes and methods
428 * @param testSuiteBuilder - builder to add tests to
429 */
430 private void parseTestClasses(String testClassArg, TestSuiteBuilder testSuiteBuilder) {
431 String[] testClasses = testClassArg.split(",");
432 for (String testClass : testClasses) {
433 parseTestClass(testClass, testSuiteBuilder);
434 }
435 }
436
437 /**
438 * Parse and load the given test class and, optionally, method
Jack Wangff1df692009-08-26 17:19:13 -0700439 *
440 * @param testClassName - full package name of test class and optionally method to add.
441 * Expected format: com.android.TestClass#testMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 * @param testSuiteBuilder - builder to add tests to
443 */
444 private void parseTestClass(String testClassName, TestSuiteBuilder testSuiteBuilder) {
445 int methodSeparatorIndex = testClassName.indexOf('#');
446 String testMethodName = null;
447
448 if (methodSeparatorIndex > 0) {
449 testMethodName = testClassName.substring(methodSeparatorIndex + 1);
450 testClassName = testClassName.substring(0, methodSeparatorIndex);
451 }
Jack Wangff1df692009-08-26 17:19:13 -0700452 testSuiteBuilder.addTestClassByName(testClassName, testMethodName, getTargetContext());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 }
454
455 protected AndroidTestRunner getAndroidTestRunner() {
456 return new AndroidTestRunner();
457 }
458
459 private boolean getBooleanArgument(Bundle arguments, String tag) {
460 String tagString = arguments.getString(tag);
461 return tagString != null && Boolean.parseBoolean(tagString);
462 }
Jack Wangff1df692009-08-26 17:19:13 -0700463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 /*
465 * Returns the size predicate object, corresponding to the "size" argument value.
466 */
467 private Predicate<TestMethod> getSizePredicateFromArg(String sizeArg) {
Jack Wangff1df692009-08-26 17:19:13 -0700468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 if (SMALL_SUITE.equals(sizeArg)) {
Paul Duffinfedb4b72017-06-22 10:47:25 +0100470 return SELECT_SMALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 } else if (MEDIUM_SUITE.equals(sizeArg)) {
Paul Duffinfedb4b72017-06-22 10:47:25 +0100472 return SELECT_MEDIUM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 } else if (LARGE_SUITE.equals(sizeArg)) {
Paul Duffinfedb4b72017-06-22 10:47:25 +0100474 return SELECT_LARGE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 } else {
476 return null;
477 }
478 }
Jack Wangff1df692009-08-26 17:19:13 -0700479
Brett Chabot88e03a92010-02-19 09:57:11 -0800480 /**
481 * Returns the test predicate object, corresponding to the annotation class value provided via
Paul Duffin575f9da2017-06-20 14:41:20 +0100482 * the {@link #ARGUMENT_ANNOTATION} argument.
Brett Chabot88e03a92010-02-19 09:57:11 -0800483 *
484 * @return the predicate or <code>null</code>
485 */
486 private Predicate<TestMethod> getAnnotationPredicate(String annotationClassName) {
487 Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
488 if (annotationClass != null) {
Paul Duffinfedb4b72017-06-22 10:47:25 +0100489 return hasAnnotation(annotationClass);
Brett Chabot88e03a92010-02-19 09:57:11 -0800490 }
491 return null;
492 }
493
494 /**
495 * Returns the negative test predicate object, corresponding to the annotation class value
Paul Duffin575f9da2017-06-20 14:41:20 +0100496 * provided via the {@link #ARGUMENT_NOT_ANNOTATION} argument.
Brett Chabot88e03a92010-02-19 09:57:11 -0800497 *
498 * @return the predicate or <code>null</code>
499 */
500 private Predicate<TestMethod> getNotAnnotationPredicate(String annotationClassName) {
501 Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
502 if (annotationClass != null) {
Paul Duffinfedb4b72017-06-22 10:47:25 +0100503 return TestPredicates.not(hasAnnotation(annotationClass));
Brett Chabot88e03a92010-02-19 09:57:11 -0800504 }
505 return null;
506 }
507
508 /**
509 * Helper method to return the annotation class with specified name
510 *
511 * @param annotationClassName the fully qualified name of the class
512 * @return the annotation class or <code>null</code>
513 */
514 private Class<? extends Annotation> getAnnotationClass(String annotationClassName) {
515 if (annotationClassName == null) {
516 return null;
517 }
518 try {
519 Class<?> annotationClass = Class.forName(annotationClassName);
520 if (annotationClass.isAnnotation()) {
521 return (Class<? extends Annotation>)annotationClass;
522 } else {
523 Log.e(LOG_TAG, String.format("Provided annotation value %s is not an Annotation",
524 annotationClassName));
525 }
526 } catch (ClassNotFoundException e) {
527 Log.e(LOG_TAG, String.format("Could not find class for specified annotation %s",
528 annotationClassName));
529 }
530 return null;
531 }
532
Brett Chabot31e7ce72010-07-07 17:19:08 -0700533 /**
534 * Initialize the current thread as a looper.
535 * <p/>
536 * Exposed for unit testing.
537 */
538 void prepareLooper() {
539 Looper.prepare();
540 }
541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 @Override
543 public void onStart() {
Brett Chabot31e7ce72010-07-07 17:19:08 -0700544 prepareLooper();
Jack Wangff1df692009-08-26 17:19:13 -0700545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 if (mJustCount) {
547 mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
548 mResults.putInt(REPORT_KEY_NUM_TOTAL, mTestCount);
549 finish(Activity.RESULT_OK, mResults);
550 } else {
551 if (mDebug) {
552 Debug.waitForDebugger();
553 }
Jack Wangff1df692009-08-26 17:19:13 -0700554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
556 PrintStream writer = new PrintStream(byteArrayOutputStream);
557 try {
558 StringResultPrinter resultPrinter = new StringResultPrinter(writer);
Jack Wangff1df692009-08-26 17:19:13 -0700559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 mTestRunner.addTestListener(resultPrinter);
Jack Wangff1df692009-08-26 17:19:13 -0700561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 long startTime = System.currentTimeMillis();
563 mTestRunner.runTest();
564 long runTime = System.currentTimeMillis() - startTime;
Jack Wangff1df692009-08-26 17:19:13 -0700565
Brett Chabot41e173d2012-10-24 14:34:07 -0700566 resultPrinter.printResult(mTestRunner.getTestResult(), runTime);
Brett Chabot31e7ce72010-07-07 17:19:08 -0700567 } catch (Throwable t) {
568 // catch all exceptions so a more verbose error message can be outputted
569 writer.println(String.format("Test run aborted due to unexpected exception: %s",
570 t.getMessage()));
571 t.printStackTrace(writer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 } finally {
Jack Wangff1df692009-08-26 17:19:13 -0700573 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
574 String.format("\nTest results for %s=%s",
575 mTestRunner.getTestClassName(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 byteArrayOutputStream.toString()));
577
578 if (mCoverage) {
579 generateCoverageReport();
580 }
581 writer.close();
Jack Wangff1df692009-08-26 17:19:13 -0700582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 finish(Activity.RESULT_OK, mResults);
584 }
585 }
586 }
587
588 public TestSuite getTestSuite() {
589 return getAllTests();
590 }
591
592 /**
593 * Override this to define all of the tests to run in your package.
594 */
595 public TestSuite getAllTests() {
596 return null;
597 }
598
599 /**
600 * Override this to provide access to the class loader of your package.
601 */
602 public ClassLoader getLoader() {
603 return null;
604 }
Jack Wangff1df692009-08-26 17:19:13 -0700605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 private void generateCoverageReport() {
607 // use reflection to call emma dump coverage method, to avoid
608 // always statically compiling against emma jar
Brett Chabot51e03642009-05-28 18:18:15 -0700609 String coverageFilePath = getCoverageFilePath();
610 java.io.File coverageFile = new java.io.File(coverageFilePath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 try {
Brett Chabot88e03a92010-02-19 09:57:11 -0800612 Class<?> emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
Jack Wangff1df692009-08-26 17:19:13 -0700613 Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 coverageFile.getClass(), boolean.class, boolean.class);
Jack Wangff1df692009-08-26 17:19:13 -0700615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 dumpCoverageMethod.invoke(null, coverageFile, false, false);
Brett Chabot51e03642009-05-28 18:18:15 -0700617 // output path to generated coverage file so it can be parsed by a test harness if
618 // needed
619 mResults.putString(REPORT_KEY_COVERAGE_PATH, coverageFilePath);
620 // also output a more user friendly msg
Brett Chabot08d13c32010-02-18 15:42:13 -0800621 final String currentStream = mResults.getString(
622 Instrumentation.REPORT_KEY_STREAMRESULT);
Brett Chabot51e03642009-05-28 18:18:15 -0700623 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
Brett Chabot08d13c32010-02-18 15:42:13 -0800624 String.format("%s\nGenerated code coverage data to %s", currentStream,
625 coverageFilePath));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 } catch (ClassNotFoundException e) {
627 reportEmmaError("Is emma jar on classpath?", e);
628 } catch (SecurityException e) {
629 reportEmmaError(e);
630 } catch (NoSuchMethodException e) {
631 reportEmmaError(e);
632 } catch (IllegalArgumentException e) {
633 reportEmmaError(e);
634 } catch (IllegalAccessException e) {
635 reportEmmaError(e);
636 } catch (InvocationTargetException e) {
637 reportEmmaError(e);
638 }
639 }
640
641 private String getCoverageFilePath() {
642 if (mCoverageFilePath == null) {
Brett Chabot51e03642009-05-28 18:18:15 -0700643 return getTargetContext().getFilesDir().getAbsolutePath() + File.separator +
Jack Wangff1df692009-08-26 17:19:13 -0700644 DEFAULT_COVERAGE_FILE_NAME;
645 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 return mCoverageFilePath;
647 }
648 }
649
650 private void reportEmmaError(Exception e) {
Jack Wangff1df692009-08-26 17:19:13 -0700651 reportEmmaError("", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 }
653
654 private void reportEmmaError(String hint, Exception e) {
655 String msg = "Failed to generate emma coverage. " + hint;
656 Log.e(LOG_TAG, msg, e);
657 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "\nError: " + msg);
658 }
659
660 // TODO kill this, use status() and prettyprint model for better output
661 private class StringResultPrinter extends ResultPrinter {
662
663 public StringResultPrinter(PrintStream writer) {
664 super(writer);
665 }
666
Brett Chabot41e173d2012-10-24 14:34:07 -0700667 public synchronized void printResult(TestResult result, long runTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 printHeader(runTime);
669 printFooter(result);
670 }
671 }
Jack Wangff1df692009-08-26 17:19:13 -0700672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 /**
Jack Wangff1df692009-08-26 17:19:13 -0700674 * This class sends status reports back to the IInstrumentationWatcher about
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 * which suite each test belongs.
676 */
Jack Wangff1df692009-08-26 17:19:13 -0700677 private class SuiteAssignmentPrinter implements TestListener {
678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 private Bundle mTestResult;
680 private long mStartTime;
681 private long mEndTime;
682 private boolean mTimingValid;
Jack Wangff1df692009-08-26 17:19:13 -0700683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 public SuiteAssignmentPrinter() {
685 }
Jack Wangff1df692009-08-26 17:19:13 -0700686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 /**
688 * send a status for the start of a each test, so long tests can be seen as "running"
689 */
690 public void startTest(Test test) {
691 mTimingValid = true;
Jack Wangff1df692009-08-26 17:19:13 -0700692 mStartTime = System.currentTimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 }
Jack Wangff1df692009-08-26 17:19:13 -0700694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 /**
696 * @see junit.framework.TestListener#addError(Test, Throwable)
697 */
698 public void addError(Test test, Throwable t) {
699 mTimingValid = false;
700 }
701
702 /**
703 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
704 */
705 public void addFailure(Test test, AssertionFailedError t) {
706 mTimingValid = false;
707 }
708
709 /**
710 * @see junit.framework.TestListener#endTest(Test)
711 */
712 public void endTest(Test test) {
713 float runTime;
714 String assignmentSuite;
715 mEndTime = System.currentTimeMillis();
716 mTestResult = new Bundle();
717
718 if (!mTimingValid || mStartTime < 0) {
719 assignmentSuite = "NA";
720 runTime = -1;
721 } else {
722 runTime = mEndTime - mStartTime;
Jack Wangff1df692009-08-26 17:19:13 -0700723 if (runTime < SMALL_SUITE_MAX_RUNTIME
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 && !InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
725 assignmentSuite = SMALL_SUITE;
726 } else if (runTime < MEDIUM_SUITE_MAX_RUNTIME) {
727 assignmentSuite = MEDIUM_SUITE;
728 } else {
729 assignmentSuite = LARGE_SUITE;
730 }
731 }
732 // Clear mStartTime so that we can verify that it gets set next time.
733 mStartTime = -1;
734
Jack Wangff1df692009-08-26 17:19:13 -0700735 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
736 test.getClass().getName() + "#" + ((TestCase) test).getName()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 + "\nin " + assignmentSuite + " suite\nrunTime: "
738 + String.valueOf(runTime) + "\n");
739 mTestResult.putFloat(REPORT_KEY_RUN_TIME, runTime);
740 mTestResult.putString(REPORT_KEY_SUITE_ASSIGNMENT, assignmentSuite);
741
742 sendStatus(0, mTestResult);
743 }
744 }
Jack Wangff1df692009-08-26 17:19:13 -0700745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 /**
747 * This class sends status reports back to the IInstrumentationWatcher
748 */
Paul Duffin5361c482017-06-15 14:50:08 +0100749 private class WatcherResultPrinter implements TestListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 private final Bundle mResultTemplate;
751 Bundle mTestResult;
752 int mTestNum = 0;
753 int mTestResultCode = 0;
754 String mTestClass = null;
Jack Wangff1df692009-08-26 17:19:13 -0700755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 public WatcherResultPrinter(int numTests) {
757 mResultTemplate = new Bundle();
758 mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
759 mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
760 }
Jack Wangff1df692009-08-26 17:19:13 -0700761
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 /**
Jack Wangff1df692009-08-26 17:19:13 -0700763 * send a status for the start of a each test, so long tests can be seen
764 * as "running"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 */
766 public void startTest(Test test) {
767 String testClass = test.getClass().getName();
Jack Wangff1df692009-08-26 17:19:13 -0700768 String testName = ((TestCase)test).getName();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 mTestResult = new Bundle(mResultTemplate);
770 mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
Jack Wangff1df692009-08-26 17:19:13 -0700771 mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
773 // pretty printing
774 if (testClass != null && !testClass.equals(mTestClass)) {
Jack Wangff1df692009-08-26 17:19:13 -0700775 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 String.format("\n%s:", testClass));
777 mTestClass = testClass;
778 } else {
779 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, "");
780 }
781
Jack Wang3fc03e62010-10-19 15:13:07 -0700782 Method testMethod = null;
783 try {
784 testMethod = test.getClass().getMethod(testName);
785 // Report total number of iterations, if test is repetitive
786 if (testMethod.isAnnotationPresent(RepetitiveTest.class)) {
787 int numIterations = testMethod.getAnnotation(
788 RepetitiveTest.class).numIterations();
789 mTestResult.putInt(REPORT_KEY_NUM_ITERATIONS, numIterations);
790 }
791 } catch (NoSuchMethodException e) {
792 // ignore- the test with given name does not exist. Will be handled during test
793 // execution
794 }
795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 // The delay_msec parameter is normally used to provide buffers of idle time
Jack Wangff1df692009-08-26 17:19:13 -0700797 // for power measurement purposes. To make sure there is a delay before and after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 // every test in a suite, we delay *after* every test (see endTest below) and also
Jack Wangff1df692009-08-26 17:19:13 -0700799 // delay *before* the first test. So, delay test1 delay test2 delay.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800
801 try {
802 if (mTestNum == 1) Thread.sleep(mDelayMsec);
803 } catch (InterruptedException e) {
804 throw new IllegalStateException(e);
805 }
806
807 sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
808 mTestResultCode = 0;
809 }
Jack Wangff1df692009-08-26 17:19:13 -0700810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 /**
812 * @see junit.framework.TestListener#addError(Test, Throwable)
813 */
814 public void addError(Test test, Throwable t) {
815 mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
816 mTestResultCode = REPORT_VALUE_RESULT_ERROR;
817 // pretty printing
Jack Wangff1df692009-08-26 17:19:13 -0700818 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
819 String.format("\nError in %s:\n%s",
820 ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 }
822
823 /**
824 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
825 */
826 public void addFailure(Test test, AssertionFailedError t) {
827 mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
828 mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
829 // pretty printing
Jack Wangff1df692009-08-26 17:19:13 -0700830 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
831 String.format("\nFailure in %s:\n%s",
832 ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800833 }
834
835 /**
836 * @see junit.framework.TestListener#endTest(Test)
837 */
838 public void endTest(Test test) {
839 if (mTestResultCode == 0) {
840 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
841 }
842 sendStatus(mTestResultCode, mTestResult);
843
Jack Wangff1df692009-08-26 17:19:13 -0700844 try { // Sleep after every test, if specified
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 Thread.sleep(mDelayMsec);
846 } catch (InterruptedException e) {
847 throw new IllegalStateException(e);
848 }
849 }
850
851 // TODO report the end of the cycle
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 }
853}