19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.test;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
20358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport java.lang.reflect.Field;
21358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport java.lang.reflect.Modifier;
22358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport java.util.List;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport com.android.internal.util.Predicate;
25358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport com.android.internal.util.Predicates;
26358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
27358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport dalvik.annotation.BrokenTest;
28358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport dalvik.annotation.SideEffect;
29358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
30358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport junit.framework.AssertionFailedError;
31358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport junit.framework.Test;
32358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport junit.framework.TestCase;
33358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport junit.framework.TestListener;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
35358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport android.test.suitebuilder.TestMethod;
36358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport android.test.suitebuilder.annotation.HasAnnotation;
37358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grobimport android.util.Log;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This test runner extends the default InstrumentationTestRunner. It overrides
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the {@code onCreate(Bundle)} method and sets the system properties necessary
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * for many core tests to run. This is needed because there are some core tests
43358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob * that need writing access to the file system. We also need to set the harness
44358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob * Thread's context ClassLoader. Otherwise some classes and resources will not
45358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob * be found. Finally, we add a means to free memory allocated by a TestCase
46358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob * after its execution.
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class InstrumentationCoreTestRunner extends InstrumentationTestRunner {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann    /**
53b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann     * Convenience definition of our log tag.
54c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson     */
55358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    private static final String TAG = "InstrumentationCoreTestRunner";
56c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
57b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann    /**
58b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann     * True if (and only if) we are running in single-test mode (as opposed to
59b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann     * batch mode).
60b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann     */
61358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    private boolean singleTest = false;
62c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onCreate(Bundle arguments) {
65358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        // We might want to move this to /sdcard, if is is mounted/writable.
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        File cacheDir = getTargetContext().getCacheDir();
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
68c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson        // Set some properties that the core tests absolutely need.
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.setProperty("user.language", "en");
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.setProperty("user.region", "US");
71c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
72358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        System.setProperty("java.home", cacheDir.getAbsolutePath());
73358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        System.setProperty("user.home", cacheDir.getAbsolutePath());
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
75c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
76358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        if (arguments != null) {
77358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            String classArg = arguments.getString(ARGUMENT_TEST_CLASS);
78c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson            singleTest = classArg != null && classArg.contains("#");
79358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        }
80c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
81358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        super.onCreate(arguments);
82358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    }
83358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
84b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann    @Override
85358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    protected AndroidTestRunner getAndroidTestRunner() {
86358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        AndroidTestRunner runner = super.getAndroidTestRunner();
87358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
88358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        runner.addTestListener(new TestListener() {
89b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            /**
90c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson             * The last test class we executed code from.
91b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             */
92358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            private Class<?> lastClass;
93c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
94b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            /**
95b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             * The minimum time we expect a test to take.
96b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             */
97b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            private static final int MINIMUM_TIME = 100;
98c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
99b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            /**
100b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             * The start time of our current test in System.currentTimeMillis().
101b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             */
102b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            private long startTime;
103c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
104358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            public void startTest(Test test) {
105358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                if (test.getClass() != lastClass) {
106b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    lastClass = test.getClass();
107358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    printMemory(test.getClass());
108358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                }
109c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
110358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Thread.currentThread().setContextClassLoader(
111358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                        test.getClass().getClassLoader());
112c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
113b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                startTime = System.currentTimeMillis();
114358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
115c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
116358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            public void endTest(Test test) {
117358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                if (test instanceof TestCase) {
118b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    cleanup((TestCase)test);
119c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
120b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    /*
121b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                     * Make sure all tests take at least MINIMUM_TIME to
122b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                     * complete. If they don't, we wait a bit. The Cupcake
123b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                     * Binder can't handle too many operations in a very
124b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                     * short time, which causes headache for the CTS.
125b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                     */
126b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    long timeTaken = System.currentTimeMillis() - startTime;
127c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
128b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    if (timeTaken < MINIMUM_TIME) {
129b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                        try {
130b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                            Thread.sleep(MINIMUM_TIME - timeTaken);
131b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                        } catch (InterruptedException ignored) {
132b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                            // We don't care.
133358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                        }
134358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    }
135358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                }
136358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
137c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
138358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            public void addError(Test test, Throwable t) {
139b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                // This space intentionally left blank.
140358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
141c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
142358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            public void addFailure(Test test, AssertionFailedError t) {
143b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                // This space intentionally left blank.
144358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
145c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
146358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            /**
147358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             * Dumps some memory info.
148358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             */
149358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            private void printMemory(Class<? extends Test> testClass) {
150358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Runtime runtime = Runtime.getRuntime();
151358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
152358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                long total = runtime.totalMemory();
153358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                long free = runtime.freeMemory();
154358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                long used = total - free;
155c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
156358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Log.d(TAG, "Total memory  : " + total);
157358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Log.d(TAG, "Used memory   : " + used);
158358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Log.d(TAG, "Free memory   : " + free);
159358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Log.d(TAG, "Now executing : " + testClass.getName());
160358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
161358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
162358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            /**
163b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             * Nulls all non-static reference fields in the given test class.
164b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann             * This method helps us with those test classes that don't have an
165358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             * explicit tearDown() method. Normally the garbage collector should
166358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             * take care of everything, but since JUnit keeps references to all
167358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             * test cases, a little help might be a good idea.
168358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob             */
169b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann            private void cleanup(TestCase test) {
170b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                Class<?> clazz = test.getClass();
171c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
172b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                while (clazz != TestCase.class) {
173358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    Field[] fields = clazz.getDeclaredFields();
174358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    for (int i = 0; i < fields.length; i++) {
175358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                        Field f = fields[i];
176358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                        if (!f.getType().isPrimitive() &&
177b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                                !Modifier.isStatic(f.getModifiers())) {
178358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                            try {
179358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                                f.setAccessible(true);
180b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                                f.set(test, null);
181358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                            } catch (Exception ignored) {
182358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                                // Nothing we can do about it.
183358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                            }
184358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                        }
185358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    }
186c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
187b867019173d20cd4fd7ee79a3ce924096e95a241Jorg Pleumann                    clazz = clazz.getSuperclass();
188358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                }
189358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            }
190c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
191358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        });
192c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson
193358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        return runner;
194c69efa5efce6d9a820f8902ca62305cddea163e6Jesse Wilson    }
195358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob
196358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    @Override
197358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob    List<Predicate<TestMethod>> getBuilderRequirements() {
198358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        List<Predicate<TestMethod>> builderRequirements =
199358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                super.getBuilderRequirements();
200358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        Predicate<TestMethod> brokenTestPredicate =
201358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                Predicates.not(new HasAnnotation(BrokenTest.class));
202358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        builderRequirements.add(brokenTestPredicate);
203358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        if (!singleTest) {
204358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            Predicate<TestMethod> sideEffectPredicate =
205358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob                    Predicates.not(new HasAnnotation(SideEffect.class));
206358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob            builderRequirements.add(sideEffectPredicate);
207358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        }
208358d23017d0d6c4636eb7599ae7a9b48108899a3Urs Grob        return builderRequirements;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
211