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 @Override 123 public void startTest(Test test) { 124 if (test.getClass() != lastClass) { 125 lastClass = test.getClass(); 126 printMemory(test.getClass()); 127 } 128 129 Thread.currentThread().setContextClassLoader( 130 test.getClass().getClassLoader()); 131 132 mEnvironment.reset(); 133 } 134 135 @Override 136 public void endTest(Test test) { 137 if (test instanceof TestCase) { 138 cleanup((TestCase)test); 139 } 140 } 141 142 @Override 143 public void addError(Test test, Throwable t) { 144 // This space intentionally left blank. 145 } 146 147 @Override 148 public void addFailure(Test test, AssertionFailedError t) { 149 // This space intentionally left blank. 150 } 151 152 /** 153 * Dumps some memory info. 154 */ 155 private void printMemory(Class<? extends Test> testClass) { 156 Runtime runtime = Runtime.getRuntime(); 157 158 long total = runtime.totalMemory(); 159 long free = runtime.freeMemory(); 160 long used = total - free; 161 162 Log.d(TAG, "Total memory : " + total); 163 Log.d(TAG, "Used memory : " + used); 164 Log.d(TAG, "Free memory : " + free); 165 Log.d(TAG, "Now executing : " + testClass.getName()); 166 } 167 168 /** 169 * Nulls all non-static reference fields in the given test class. 170 * This method helps us with those test classes that don't have an 171 * explicit tearDown() method. Normally the garbage collector should 172 * take care of everything, but since JUnit keeps references to all 173 * test cases, a little help might be a good idea. 174 */ 175 private void cleanup(TestCase test) { 176 Class<?> clazz = test.getClass(); 177 178 while (clazz != TestCase.class) { 179 Field[] fields = clazz.getDeclaredFields(); 180 for (int i = 0; i < fields.length; i++) { 181 Field f = fields[i]; 182 if (!f.getType().isPrimitive() && 183 !Modifier.isStatic(f.getModifiers())) { 184 try { 185 f.setAccessible(true); 186 f.set(test, null); 187 } catch (Exception ignored) { 188 // Nothing we can do about it. 189 } 190 } 191 } 192 193 clazz = clazz.getSuperclass(); 194 } 195 } 196 197 }); 198 199 return runner; 200 } 201 202 // http://code.google.com/p/vogar/source/browse/trunk/src/vogar/target/TestEnvironment.java 203 static class TestEnvironment { 204 private Locale mDefaultLocale; 205 private String mUserHome; 206 private String mJavaIoTmpDir; 207 private HostnameVerifier mHostnameVerifier; 208 private SSLSocketFactory mSslSocketFactory; 209 210 TestEnvironment() { 211 mDefaultLocale = Locale.getDefault(); 212 mUserHome = System.getProperty("user.home"); 213 mJavaIoTmpDir = System.getProperty("java.io.tmpdir"); 214 mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); 215 mSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); 216 } 217 218 void reset() { 219 Locale.setDefault(mDefaultLocale); 220 System.setProperty("user.home", mUserHome); 221 System.setProperty("java.io.tmpdir", mJavaIoTmpDir); 222 Authenticator.setDefault(null); 223 CookieHandler.setDefault(null); 224 ResponseCache.setDefault(null); 225 HttpsURLConnection.setDefaultHostnameVerifier(mHostnameVerifier); 226 HttpsURLConnection.setDefaultSSLSocketFactory(mSslSocketFactory); 227 } 228 } 229 230 @Override 231 List<Predicate<TestMethod>> getBuilderRequirements() { 232 List<Predicate<TestMethod>> builderRequirements = 233 super.getBuilderRequirements(); 234 235 Predicate<TestMethod> brokenTestPredicate = 236 Predicates.not(new HasAnnotation(BrokenTest.class)); 237 builderRequirements.add(brokenTestPredicate); 238 239 if (!mSingleTest) { 240 Predicate<TestMethod> sideEffectPredicate = 241 Predicates.not(new HasAnnotation(SideEffect.class)); 242 builderRequirements.add(sideEffectPredicate); 243 } 244 return builderRequirements; 245 } 246 } 247