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 onCreate(Bundle arguments)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 TimeZone.setDefault(TimeZone.getTimeZone("GMT")); 89 90 mEnvironment = new TestEnvironment(); 91 92 if (arguments != null) { 93 String classArg = arguments.getString(ARGUMENT_TEST_CLASS); 94 mSingleTest = classArg != null && classArg.contains("#"); 95 } 96 97 // attempt to disable keyguard, if current test has permission to do so 98 // TODO: move this to a better place, such as InstrumentationTestRunner ? 99 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 100 == PackageManager.PERMISSION_GRANTED) { 101 Log.i(TAG, "Disabling keyguard"); 102 KeyguardManager keyguardManager = 103 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); 104 keyguardManager.newKeyguardLock("cts").disableKeyguard(); 105 } else { 106 Log.i(TAG, "Test lacks permission to disable keyguard. " + 107 "UI based tests may fail if keyguard is up"); 108 } 109 110 super.onCreate(arguments); 111 } 112 113 @Override getAndroidTestRunner()114 protected AndroidTestRunner getAndroidTestRunner() { 115 AndroidTestRunner runner = super.getAndroidTestRunner(); 116 117 runner.addTestListener(new TestListener() { 118 /** 119 * The last test class we executed code from. 120 */ 121 private Class<?> lastClass; 122 123 /** 124 * The minimum time we expect a test to take. 125 */ 126 private static final int MINIMUM_TIME = 100; 127 128 /** 129 * The start time of our current test in System.currentTimeMillis(). 130 */ 131 private long startTime; 132 133 @Override 134 public void startTest(Test test) { 135 if (test.getClass() != lastClass) { 136 lastClass = test.getClass(); 137 printMemory(test.getClass()); 138 } 139 140 Thread.currentThread().setContextClassLoader( 141 test.getClass().getClassLoader()); 142 143 mEnvironment.reset(); 144 145 startTime = System.currentTimeMillis(); 146 } 147 148 @Override 149 public void endTest(Test test) { 150 if (test instanceof TestCase) { 151 cleanup((TestCase)test); 152 153 /* 154 * Make sure all tests take at least MINIMUM_TIME to 155 * complete. If they don't, we wait a bit. The Cupcake 156 * Binder can't handle too many operations in a very 157 * short time, which causes headache for the CTS. 158 */ 159 long timeTaken = System.currentTimeMillis() - startTime; 160 161 if (timeTaken < MINIMUM_TIME) { 162 try { 163 Thread.sleep(MINIMUM_TIME - timeTaken); 164 } catch (InterruptedException ignored) { 165 // We don't care. 166 } 167 } 168 } 169 } 170 171 @Override 172 public void addError(Test test, Throwable t) { 173 // This space intentionally left blank. 174 } 175 176 @Override 177 public void addFailure(Test test, AssertionFailedError t) { 178 // This space intentionally left blank. 179 } 180 181 /** 182 * Dumps some memory info. 183 */ 184 private void printMemory(Class<? extends Test> testClass) { 185 Runtime runtime = Runtime.getRuntime(); 186 187 long total = runtime.totalMemory(); 188 long free = runtime.freeMemory(); 189 long used = total - free; 190 191 Log.d(TAG, "Total memory : " + total); 192 Log.d(TAG, "Used memory : " + used); 193 Log.d(TAG, "Free memory : " + free); 194 Log.d(TAG, "Now executing : " + testClass.getName()); 195 } 196 197 /** 198 * Nulls all non-static reference fields in the given test class. 199 * This method helps us with those test classes that don't have an 200 * explicit tearDown() method. Normally the garbage collector should 201 * take care of everything, but since JUnit keeps references to all 202 * test cases, a little help might be a good idea. 203 */ 204 private void cleanup(TestCase test) { 205 Class<?> clazz = test.getClass(); 206 207 while (clazz != TestCase.class) { 208 Field[] fields = clazz.getDeclaredFields(); 209 for (int i = 0; i < fields.length; i++) { 210 Field f = fields[i]; 211 if (!f.getType().isPrimitive() && 212 !Modifier.isStatic(f.getModifiers())) { 213 try { 214 f.setAccessible(true); 215 f.set(test, null); 216 } catch (Exception ignored) { 217 // Nothing we can do about it. 218 } 219 } 220 } 221 222 clazz = clazz.getSuperclass(); 223 } 224 } 225 226 }); 227 228 return runner; 229 } 230 231 // http://code.google.com/p/vogar/source/browse/trunk/src/vogar/target/TestEnvironment.java 232 static class TestEnvironment { 233 private Locale mDefaultLocale; 234 private String mUserHome; 235 private String mJavaIoTmpDir; 236 private HostnameVerifier mHostnameVerifier; 237 private SSLSocketFactory mSslSocketFactory; 238 TestEnvironment()239 TestEnvironment() { 240 mDefaultLocale = Locale.getDefault(); 241 mUserHome = System.getProperty("user.home"); 242 mJavaIoTmpDir = System.getProperty("java.io.tmpdir"); 243 mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); 244 mSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); 245 } 246 reset()247 void reset() { 248 Locale.setDefault(mDefaultLocale); 249 System.setProperty("user.home", mUserHome); 250 System.setProperty("java.io.tmpdir", mJavaIoTmpDir); 251 Authenticator.setDefault(null); 252 CookieHandler.setDefault(null); 253 ResponseCache.setDefault(null); 254 HttpsURLConnection.setDefaultHostnameVerifier(mHostnameVerifier); 255 HttpsURLConnection.setDefaultSSLSocketFactory(mSslSocketFactory); 256 } 257 } 258 259 @Override getBuilderRequirements()260 List<Predicate<TestMethod>> getBuilderRequirements() { 261 List<Predicate<TestMethod>> builderRequirements = 262 super.getBuilderRequirements(); 263 264 Predicate<TestMethod> brokenTestPredicate = 265 Predicates.not(new HasAnnotation(BrokenTest.class)); 266 builderRequirements.add(brokenTestPredicate); 267 268 if (!mSingleTest) { 269 Predicate<TestMethod> sideEffectPredicate = 270 Predicates.not(new HasAnnotation(SideEffect.class)); 271 builderRequirements.add(sideEffectPredicate); 272 } 273 return builderRequirements; 274 } 275 } 276