Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 | |
| 17 | package android.test; |
| 18 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 19 | import com.android.internal.util.Predicate; |
| 20 | import com.android.internal.util.Predicates; |
| 21 | |
| 22 | import dalvik.annotation.BrokenTest; |
| 23 | import dalvik.annotation.SideEffect; |
| 24 | |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 25 | import android.app.KeyguardManager; |
| 26 | import android.content.Context; |
| 27 | import android.content.pm.PackageManager; |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 28 | import android.os.Bundle; |
| 29 | import android.test.suitebuilder.TestMethod; |
| 30 | import android.test.suitebuilder.annotation.HasAnnotation; |
| 31 | import android.util.Log; |
| 32 | |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 33 | import java.io.File; |
| 34 | import java.lang.reflect.Field; |
| 35 | import java.lang.reflect.Modifier; |
| 36 | import java.util.List; |
| 37 | import java.util.TimeZone; |
| 38 | |
| 39 | import junit.framework.AssertionFailedError; |
| 40 | import junit.framework.Test; |
| 41 | import junit.framework.TestCase; |
| 42 | import junit.framework.TestListener; |
| 43 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 44 | /** |
| 45 | * This test runner extends the default InstrumentationTestRunner. It overrides |
| 46 | * the {@code onCreate(Bundle)} method and sets the system properties necessary |
| 47 | * for many core tests to run. This is needed because there are some core tests |
| 48 | * that need writing access to the file system. We also need to set the harness |
| 49 | * Thread's context ClassLoader. Otherwise some classes and resources will not |
| 50 | * be found. Finally, we add a means to free memory allocated by a TestCase |
| 51 | * after its execution. |
| 52 | * |
| 53 | * @hide |
| 54 | */ |
| 55 | public class InstrumentationCtsTestRunner extends InstrumentationTestRunner { |
| 56 | |
| 57 | /** |
| 58 | * Convenience definition of our log tag. |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 59 | */ |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 60 | private static final String TAG = "InstrumentationCtsTestRunner"; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 61 | |
Brian Muramatsu | 168beb0 | 2010-10-21 12:39:45 -0700 | [diff] [blame] | 62 | private static final String REPORT_VALUE_ID = "InstrumentationCtsTestRunner"; |
| 63 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 64 | /** |
| 65 | * True if (and only if) we are running in single-test mode (as opposed to |
| 66 | * batch mode). |
| 67 | */ |
Brian Muramatsu | 7bc0e8e | 2010-08-24 12:24:18 -0700 | [diff] [blame] | 68 | private boolean mSingleTest = false; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 69 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 70 | @Override |
| 71 | public void onCreate(Bundle arguments) { |
| 72 | // We might want to move this to /sdcard, if is is mounted/writable. |
| 73 | File cacheDir = getTargetContext().getCacheDir(); |
| 74 | |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 75 | // Set some properties that the core tests absolutely need. |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 76 | System.setProperty("user.language", "en"); |
| 77 | System.setProperty("user.region", "US"); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 78 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 79 | System.setProperty("java.home", cacheDir.getAbsolutePath()); |
| 80 | System.setProperty("user.home", cacheDir.getAbsolutePath()); |
| 81 | System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath()); |
Brett Chabot | 40e5ac6 | 2010-11-09 19:47:41 -0800 | [diff] [blame] | 82 | System.setProperty("user.dir", cacheDir.getAbsolutePath()); |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 83 | System.setProperty("javax.net.ssl.trustStore", |
| 84 | "/etc/security/cacerts.bks"); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 85 | |
Jorg Pleumann | 43ad2f6 | 2009-05-07 09:27:16 -0700 | [diff] [blame] | 86 | TimeZone.setDefault(TimeZone.getTimeZone("GMT")); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 87 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 88 | if (arguments != null) { |
| 89 | String classArg = arguments.getString(ARGUMENT_TEST_CLASS); |
Brian Muramatsu | 7bc0e8e | 2010-08-24 12:24:18 -0700 | [diff] [blame] | 90 | mSingleTest = classArg != null && classArg.contains("#"); |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 91 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 92 | |
| 93 | // attempt to disable keyguard, if current test has permission to do so |
| 94 | // TODO: move this to a better place, such as InstrumentationTestRunner ? |
| 95 | if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) |
| 96 | == PackageManager.PERMISSION_GRANTED) { |
| 97 | Log.i(TAG, "Disabling keyguard"); |
| 98 | KeyguardManager keyguardManager = |
| 99 | (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); |
| 100 | keyguardManager.newKeyguardLock("cts").disableKeyguard(); |
| 101 | } else { |
| 102 | Log.i(TAG, "Test lacks permission to disable keyguard. " + |
| 103 | "UI based tests may fail if keyguard is up"); |
| 104 | } |
| 105 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 106 | super.onCreate(arguments); |
| 107 | } |
| 108 | |
| 109 | @Override |
| 110 | protected AndroidTestRunner getAndroidTestRunner() { |
| 111 | AndroidTestRunner runner = super.getAndroidTestRunner(); |
| 112 | |
| 113 | runner.addTestListener(new TestListener() { |
| 114 | /** |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 115 | * The last test class we executed code from. |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 116 | */ |
| 117 | private Class<?> lastClass; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 118 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 119 | /** |
| 120 | * The minimum time we expect a test to take. |
| 121 | */ |
| 122 | private static final int MINIMUM_TIME = 100; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 123 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 124 | /** |
| 125 | * The start time of our current test in System.currentTimeMillis(). |
| 126 | */ |
| 127 | private long startTime; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 128 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 129 | public void startTest(Test test) { |
| 130 | if (test.getClass() != lastClass) { |
| 131 | lastClass = test.getClass(); |
| 132 | printMemory(test.getClass()); |
| 133 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 134 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 135 | Thread.currentThread().setContextClassLoader( |
| 136 | test.getClass().getClassLoader()); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 137 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 138 | startTime = System.currentTimeMillis(); |
| 139 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 140 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 141 | public void endTest(Test test) { |
| 142 | if (test instanceof TestCase) { |
| 143 | cleanup((TestCase)test); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 144 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 145 | /* |
| 146 | * Make sure all tests take at least MINIMUM_TIME to |
| 147 | * complete. If they don't, we wait a bit. The Cupcake |
| 148 | * Binder can't handle too many operations in a very |
| 149 | * short time, which causes headache for the CTS. |
| 150 | */ |
| 151 | long timeTaken = System.currentTimeMillis() - startTime; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 152 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 153 | if (timeTaken < MINIMUM_TIME) { |
| 154 | try { |
| 155 | Thread.sleep(MINIMUM_TIME - timeTaken); |
| 156 | } catch (InterruptedException ignored) { |
| 157 | // We don't care. |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 162 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 163 | public void addError(Test test, Throwable t) { |
| 164 | // This space intentionally left blank. |
| 165 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 166 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 167 | public void addFailure(Test test, AssertionFailedError t) { |
| 168 | // This space intentionally left blank. |
| 169 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 170 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 171 | /** |
| 172 | * Dumps some memory info. |
| 173 | */ |
| 174 | private void printMemory(Class<? extends Test> testClass) { |
| 175 | Runtime runtime = Runtime.getRuntime(); |
| 176 | |
| 177 | long total = runtime.totalMemory(); |
| 178 | long free = runtime.freeMemory(); |
| 179 | long used = total - free; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 180 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 181 | Log.d(TAG, "Total memory : " + total); |
| 182 | Log.d(TAG, "Used memory : " + used); |
| 183 | Log.d(TAG, "Free memory : " + free); |
| 184 | Log.d(TAG, "Now executing : " + testClass.getName()); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Nulls all non-static reference fields in the given test class. |
| 189 | * This method helps us with those test classes that don't have an |
| 190 | * explicit tearDown() method. Normally the garbage collector should |
| 191 | * take care of everything, but since JUnit keeps references to all |
| 192 | * test cases, a little help might be a good idea. |
| 193 | */ |
| 194 | private void cleanup(TestCase test) { |
| 195 | Class<?> clazz = test.getClass(); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 196 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 197 | while (clazz != TestCase.class) { |
| 198 | Field[] fields = clazz.getDeclaredFields(); |
| 199 | for (int i = 0; i < fields.length; i++) { |
| 200 | Field f = fields[i]; |
| 201 | if (!f.getType().isPrimitive() && |
| 202 | !Modifier.isStatic(f.getModifiers())) { |
| 203 | try { |
| 204 | f.setAccessible(true); |
| 205 | f.set(test, null); |
| 206 | } catch (Exception ignored) { |
| 207 | // Nothing we can do about it. |
| 208 | } |
| 209 | } |
| 210 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 211 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 212 | clazz = clazz.getSuperclass(); |
| 213 | } |
| 214 | } |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 215 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 216 | }); |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 217 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 218 | return runner; |
Brett Chabot | 5744152 | 2010-04-21 11:17:14 -0700 | [diff] [blame] | 219 | } |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 220 | |
| 221 | @Override |
| 222 | List<Predicate<TestMethod>> getBuilderRequirements() { |
| 223 | List<Predicate<TestMethod>> builderRequirements = |
| 224 | super.getBuilderRequirements(); |
Brian Muramatsu | 7bc0e8e | 2010-08-24 12:24:18 -0700 | [diff] [blame] | 225 | |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 226 | Predicate<TestMethod> brokenTestPredicate = |
| 227 | Predicates.not(new HasAnnotation(BrokenTest.class)); |
| 228 | builderRequirements.add(brokenTestPredicate); |
Brian Muramatsu | 7bc0e8e | 2010-08-24 12:24:18 -0700 | [diff] [blame] | 229 | |
Brian Muramatsu | 7bc0e8e | 2010-08-24 12:24:18 -0700 | [diff] [blame] | 230 | if (!mSingleTest) { |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 231 | Predicate<TestMethod> sideEffectPredicate = |
| 232 | Predicates.not(new HasAnnotation(SideEffect.class)); |
| 233 | builderRequirements.add(sideEffectPredicate); |
| 234 | } |
| 235 | return builderRequirements; |
| 236 | } |
Jorg Pleumann | 8a6c9f9 | 2009-05-07 01:33:15 -0700 | [diff] [blame] | 237 | } |