TestSuiteFactory.java revision f6c387128427e121477c1b32ad35cdcaa5101ba3
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 17package tests; 18 19import dalvik.annotation.AndroidOnly; 20import dalvik.annotation.KnownFailure; 21 22import junit.extensions.TestSetup; 23import junit.framework.AssertionFailedError; 24import junit.framework.Protectable; 25import junit.framework.Test; 26import junit.framework.TestCase; 27import junit.framework.TestResult; 28import junit.framework.TestSuite; 29 30import java.io.PrintWriter; 31import java.io.StringWriter; 32import java.lang.annotation.Annotation; 33import java.lang.reflect.Method; 34import java.lang.reflect.Modifier; 35import java.util.Vector; 36 37/** 38 * an enhanced TestSuite e.g. for running RI tests. 39 * 40 * a sample command line: 41 * 42 * /usr/lib/jvm/java-1.5.0-sun/bin/java -Xmx1024m -Dcts.listOnlyFailingTests=true 43 * -Dcts.includeKnownFailure=false -Dcts.runOnDalvikVM=false 44 * -Dcts.allowUnderscoreTests=false -Dcts.useEnhancedJunit=true 45 * -Dcts.collectOnly=false 46 * -cp 47 * /tmp/cts_outjavac: 48 * out/debug/host/linux-x86/product/sim/data/app/CtsCoreTests.apk: 49 * out/debug/target/common/obj/APPS/CtsCoreTests_intermediates/classes.jar: 50 * tools/cts/vm-tests/lib/junit.jar 51 * 52 * junit.textui.TestRunner tests.AllTests 53 * 54 */ 55public class TestSuiteFactory { 56 57 58 59 static boolean _collectOnly = false; 60 static boolean _useEnhancedJunit = false; 61 static boolean _allowUnderscoreTests = false; 62 static boolean _runOnDalvikVM = true; 63 static boolean _includeKnowFailure = false; 64 static boolean _listOnlyFailingTests = false; 65 static boolean _useSuppliedTestResult = false; 66 static int _maxRunningTimePerTest = 15000; // 15 seconds 67 68 static { 69 _useEnhancedJunit = System.getProperty("cts.useEnhancedJunit", "false").equals("true"); 70 // next only applicable if _useEnhancedJunit 71 _collectOnly = System.getProperty("cts.collectOnly", "false").equals("true"); 72 _allowUnderscoreTests= System.getProperty("cts.allowUnderscoreTests", "false").equals("true"); 73 _runOnDalvikVM = System.getProperty("cts.runOnDalvikVM", "true").equals("true"); 74 _includeKnowFailure = System.getProperty("cts.includeKnownFailure", "false").equals("true"); 75 _maxRunningTimePerTest = Integer.parseInt(System.getProperty("cts.maxRunningTimePerTest", "15000")); 76 _listOnlyFailingTests = System.getProperty("cts.listOnlyFailingTests", "false").equals("true"); 77 _useSuppliedTestResult = System.getProperty("cts.useSuppliedTestResult", "false").equals("true"); 78 79 System.out.println("TestSuiteFactory: v0.97"); 80 System.out.println("TestSuiteFactory: using cts.useEnhancedJunit: "+_useEnhancedJunit); 81 System.out.println("TestSuiteFactory: using cts.collectOnly: "+_collectOnly); 82 System.out.println("TestSuiteFactory: max allowed running time per test (using Thread.stop()) (cts.maxRunningTimePerTest): "+_maxRunningTimePerTest); 83 System.out.println("TestSuiteFactory: run tests on a dalvik vm (cts.runOnDalvikVM): "+_runOnDalvikVM); 84 System.out.println("TestSuiteFactory: include @KnowFailure when running on dalvik vm (cts.includeKnownFailure): "+_includeKnowFailure); 85 System.out.println("TestSuiteFactory: include '_test...' methods in test run (cts.allowUnderscoreTests): "+_allowUnderscoreTests); 86 System.out.println("TestSuiteFactory: list only failing tests (cts.listOnlyFailingTests): "+_listOnlyFailingTests); 87 System.out.println(); 88 } 89 90 public static TestSuite createTestSuite(String name) { 91 return _useEnhancedJunit? new MyTestSuite(name): new TestSuite(name); 92 } 93 94 public static TestSuite createTestSuite() { 95 return _useEnhancedJunit? new MyTestSuite(): new TestSuite(); 96 } 97 98} 99 100 101class MyTestSuite extends TestSuite { 102 private boolean allow_underscoretests = true; 103 104 public MyTestSuite() { 105 } 106 107 public MyTestSuite(String name) { 108 super(name); 109 } 110 111 public MyTestSuite(final Class theClass) { 112 String fName = theClass.getName(); 113 try { 114 TestSuite.getTestConstructor(theClass); // Avoid generating multiple error 115 // messages 116 } catch (NoSuchMethodException e) { 117 addTest(warning("Class " 118 + theClass.getName() 119 + " has no public constructor TestCase(String name) or TestCase()")); 120 return; 121 } 122 123 if (!Modifier.isPublic(theClass.getModifiers())) { 124 addTest(warning("Class " + theClass.getName() + " is not public")); 125 return; 126 } 127 128 Class superClass = theClass; 129 Vector names = new Vector(); 130 while (Test.class.isAssignableFrom(superClass)) { 131 Method[] methods = superClass.getDeclaredMethods(); 132 for (int i = 0; i < methods.length; i++) { 133 addTestMethod(methods[i], names, theClass); 134 } 135 superClass = superClass.getSuperclass(); 136 } 137 if (testCount() == 0) 138 addTest(warning("No tests found in " + theClass.getName())); 139 } 140 141 private void addTestMethod(Method m, Vector names, Class theClass) { 142 String name = m.getName(); 143 if (names.contains(name)) return; 144 if (!isPublicTestMethod(m)) { 145 if (isTestMethod(m)) 146 addTest(warning("Test method isn't public: " + m.getName())); 147 return; 148 } 149 names.addElement(name); 150 addTest(TestSuite.createTest(theClass, name)); 151 } 152 153 private boolean isPublicTestMethod(Method m) { 154 return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); 155 } 156 157 private boolean isTestMethod(Method m) { 158 String name = m.getName(); 159 Class[] parameters = m.getParameterTypes(); 160 Class returnType = m.getReturnType(); 161 return parameters.length == 0 && 162 (name.startsWith("test") || (TestSuiteFactory._allowUnderscoreTests && name.startsWith("_test"))) 163 && returnType.equals(Void.TYPE); 164 } 165 166 public void addTestSuite(Class testClass) { 167 try { 168 addTest(new MyTestSuite(testClass)); 169 } catch (Throwable e) { 170 System.err.println("---------------- error ----------------------"); 171 System.err.println("error: could not add test suite: " 172 + testClass.getName()); 173 e.printStackTrace(); 174 System.err.println("---------------- ----------------------------"); 175 } 176 } 177 178 private static int testCnt = 0; 179 180 public void runTest(Test test, final TestResult dummy_result) { 181 182 if (TestSuiteFactory._useSuppliedTestResult) { 183 if (test instanceof TestSetup) { 184 test = ((TestSetup)test).getTest(); 185 } 186 test.run(dummy_result); 187 return; 188 } 189 190 TestResult eresult = new TestResult() { 191 private String msg; 192 private boolean error = false; 193 194 protected void run(final TestCase testcase) { 195 msg = ""; 196 String testName = testcase.getClass().getName() + ":" + testcase.getName()+" (nr:"+(++testCnt)+")"; 197 try { 198 if (!TestSuiteFactory._listOnlyFailingTests) { 199 System.out.print(testName+" "); 200 } 201 Annotation aKnownFailure = null; 202 Annotation aAndroidOnly = null; 203 if (true) { // handle annotations, allow them on both class (valid for all methods then) and method level 204 // @KnownFailure("Fails because of a defect in ...") if the test is correct but there is a bug in the core libraries implementation. 205 // @BrokenTest("This test is not implemented correctly because...") if there is a defect in the test method itself. 206 // @AndroidOnly("Because...") if the test is Android-specific, succeeds on Android but fails on the JDK. 207 try { 208 Annotation[] annosClass = testcase.getClass().getDeclaredAnnotations(); 209 Method runMethod= testcase.getClass().getMethod(testcase.getName()); 210 Annotation[] annosMethod = runMethod.getDeclaredAnnotations(); 211 Annotation[] annos = null; 212 for (int i = 0; i < 2; i++) { 213 annos = (i==0? annosClass : annosMethod); 214 if (annos != null && annos.length > 0) { 215 for (Annotation anno : annos) { 216 Class<? extends Annotation> acla = anno.annotationType(); 217 if (acla.getName().equals("dalvik.annotation.AndroidOnly")) { 218 aAndroidOnly = anno; 219 } else if (acla.getName().equals("dalvik.annotation.KnownFailure")) { 220 aKnownFailure = anno; 221 } 222 } 223 } 224 } 225 } catch (NoSuchMethodException e) { 226 error = true; 227 msg +="::warning::unable to get test method to read annotations: testcase name="+testcase.getName(); 228 } 229 } 230 boolean androidOnly = aAndroidOnly != null; 231 boolean knownFailure = aKnownFailure != null; 232 233 if ( 234 !TestSuiteFactory._collectOnly 235 && ( 236 (TestSuiteFactory._runOnDalvikVM && 237 (TestSuiteFactory._includeKnowFailure || !knownFailure) 238 ) 239 || 240 (!TestSuiteFactory._runOnDalvikVM && !androidOnly) 241 ) 242 ) { 243 244 msg += "["; 245 long start = System.currentTimeMillis(); 246 // -----start the test ---- 247 startTest(testcase); 248 final Protectable p= new Protectable() { 249 public void protect() throws Throwable { 250 testcase.runBare(); 251 } 252 }; 253 boolean threadStopForced = false; 254 if (!TestSuiteFactory._runOnDalvikVM) { 255 // for jvm, start in a new thread, since we can stop() it for too-long running processes. 256 Thread t = new Thread(new Runnable(){ 257 public void run() { 258 try { 259 p.protect(); 260 } 261 catch (AssertionFailedError e) { 262 addFailure(testcase, e); 263 } 264 catch (ThreadDeath e) { // don't catch ThreadDeath by accident 265 throw e; 266 } 267 catch (Throwable e) { 268 addError(testcase, e); 269 } 270 }}); 271 t.start(); 272 273 try { 274 //System.out.println("joining..."); 275 t.join(TestSuiteFactory._maxRunningTimePerTest); 276 //System.out.println("joining done..."); 277 } catch (InterruptedException e) { 278 // ignore 279 } 280 if (t.isAlive()) { 281 threadStopForced = true; 282 } 283 t.stop(); 284 285 // for RI vm : run in new thread and stop thread after a timeout 286 } else { 287 runProtected(testcase, p); 288 } 289 290 endTest(testcase); 291 // ------------------------ 292 293 msg += "]"; 294 long stop = System.currentTimeMillis(); 295 if (threadStopForced) { 296 error = true; 297 msg += "::warning::slow test forced to stop since it took longer than "+ TestSuiteFactory._maxRunningTimePerTest; 298 } else if (stop - start > TestSuiteFactory._maxRunningTimePerTest) { 299 error = true; 300 msg += "::warning::slow test took longer than "+ TestSuiteFactory._maxRunningTimePerTest+" milis: "+(stop-start)+" milis. "; 301 } 302 303 } 304 if (!TestSuiteFactory._runOnDalvikVM && androidOnly) { 305 msg+= "ignoring on RI since @AndroidOnly: "+((AndroidOnly)aAndroidOnly).value(); 306 } 307 if (TestSuiteFactory._runOnDalvikVM && knownFailure && !TestSuiteFactory._includeKnowFailure) { 308 msg += "ignoring on dalvik since @KnownFailure: "+((KnownFailure)aKnownFailure).value(); 309 } 310 } 311 finally { 312 if (TestSuiteFactory._listOnlyFailingTests) { 313 if (error) { 314 // we have error / warnings 315 msg = testName + msg; 316 System.out.println(msg); 317 } // else do not output anything 318 } else { 319 System.out.println(msg+(error? "": " cts-test-passed")); 320 } 321 } 322 } 323 324 public synchronized void addError(Test test, Throwable t) { 325 error = true; 326 msg+= " ::error::err:"+exceptionToString(t); 327 super.addError(test, t); 328 } 329 330 public synchronized void addFailure(Test test, 331 AssertionFailedError t) { 332 error = true; 333 msg+= " ::error::failure:"+exceptionToString(t); 334 super.addFailure(test, t); 335 } 336 }; 337 test.run(eresult); 338 } 339 340 private static Test warning(final String message) { 341 return new TestCase("warning") { 342 protected void runTest() { 343 fail(message); 344 } 345 }; 346 } 347 348 private static String exceptionToString(Throwable t) { 349 StringWriter stringWriter = new StringWriter(); 350 PrintWriter writer = new PrintWriter(stringWriter); 351 t.printStackTrace(writer); 352 return stringWriter.toString(); 353 354 } 355} 356