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