TestRequestBuilder.java revision 596c213fe3d9b8035ceb868b23cebc39dc2a3636
1bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/* 2bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Copyright (C) 2012 The Android Open Source Project 3bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 4bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License"); 5bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * you may not use this file except in compliance with the License. 6bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * You may obtain a copy of the License at 7bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 8bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * http://www.apache.org/licenses/LICENSE-2.0 9bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 10bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Unless required by applicable law or agreed to in writing, software 11bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS, 12bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * See the License for the specific language governing permissions and 14bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * limitations under the License. 15bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 16bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotpackage com.android.test.runner; 17bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 1853196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport android.app.Instrumentation; 195e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.LargeTest; 205e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.MediumTest; 215e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.SmallTest; 2216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabotimport android.test.suitebuilder.annotation.Suppress; 23bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport android.util.Log; 24bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 25bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ChainedClassNameFilter; 26bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ExcludePackageNameFilter; 27bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ExternalClassNameFilter; 28bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 2953196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Computer; 300e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabotimport org.junit.runner.Description; 31bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.Request; 3253196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Runner; 33bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.manipulation.Filter; 3453196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runners.model.InitializationError; 35bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 36bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.IOException; 37bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.PrintStream; 385e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport java.lang.annotation.Annotation; 39bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Arrays; 40bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collection; 41bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collections; 42596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Rootimport java.util.regex.Pattern; 43bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 44bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/** 45bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Builds a {@link Request} from test classes in given apk paths, filtered on provided set of 46bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * restrictions. 47bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 48bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotpublic class TestRequestBuilder { 49bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 50bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private static final String LOG_TAG = "TestRequestBuilder"; 51bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 529dba8dea5781124be4e0848adba21215e622052fBrett Chabot public static final String LARGE_SIZE = "large"; 539dba8dea5781124be4e0848adba21215e622052fBrett Chabot public static final String MEDIUM_SIZE = "medium"; 549dba8dea5781124be4e0848adba21215e622052fBrett Chabot public static final String SMALL_SIZE = "small"; 559dba8dea5781124be4e0848adba21215e622052fBrett Chabot 56bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private String[] mApkPaths; 570e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private TestLoader mTestLoader; 5816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Filter mFilter = new AnnotationExclusionFilter(Suppress.class); 590e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private PrintStream mWriter; 603604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot private boolean mSkipExecution = false; 610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 625e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 635e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Filter that only runs tests whose method or class has been annotated with given filter. 645e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 655e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private static class AnnotationInclusionFilter extends Filter { 665e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 675e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 685e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 695e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot AnnotationInclusionFilter(Class<? extends Annotation> annotation) { 705e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mAnnotationClass = annotation; 715e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 725e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 735e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 745e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 755e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 765e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 775e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public boolean shouldRun(Description description) { 785e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot if (description.isTest()) { 795e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return description.getAnnotation(mAnnotationClass) != null || 805e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot description.getTestClass().isAnnotationPresent(mAnnotationClass); 815e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 825e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot // don't filter out any test classes/suites, because their methods may have correct 835e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot // annotation 845e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return true; 855e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 865e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 875e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 885e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 895e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 905e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 915e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 925e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public String describe() { 935e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return String.format("annotation %s", mAnnotationClass.getName()); 945e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 955e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 965e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 9716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 9816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Filter out tests whose method or class has been annotated with given filter. 9916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 10016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private static class AnnotationExclusionFilter extends Filter { 10116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 10216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 10316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 10416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot AnnotationExclusionFilter(Class<? extends Annotation> annotation) { 10516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mAnnotationClass = annotation; 10616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 10716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 10816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 10916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 11016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 11116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 11216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public boolean shouldRun(Description description) { 113596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root final Class<?> testClass = description.getTestClass(); 114596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 115596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /* Parameterized tests have no test classes. */ 116596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass == null) { 117596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 118596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 119596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 120596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass.isAnnotationPresent(mAnnotationClass) || 12116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot description.getAnnotation(mAnnotationClass) != null) { 12216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return false; 12316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } else { 12416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return true; 12516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 12616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 12716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 12816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 12916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 13016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 13116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 13216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public String describe() { 13316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return String.format("not annotation %s", mAnnotationClass.getName()); 13416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 1370e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public TestRequestBuilder(PrintStream writer, String... apkPaths) { 138bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mApkPaths = apkPaths; 1390e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader = new TestLoader(writer); 140bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 141bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 142bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 1430e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Add a test class to be executed. All test methods in this class will be executed. 144bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 1450e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * @param className 146bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 147bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public void addTestClass(String className) { 1480e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadClass(className); 149bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 150bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 1510e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 1520e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Adds a test method to run. 1530e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 1540e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Currently only supports one test method to be run. 1550e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 1560e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public void addTestMethod(String testClassName, String testMethodName) { 1570e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Class<?> clazz = mTestLoader.loadClass(testClassName); 1580e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (clazz != null) { 159596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root mFilter = mFilter.intersect(matchParameterizedMethod( 1600e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Description.createTestDescription(clazz, testMethodName))); 1610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1620e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1630e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 1640e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 165596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * A filter to get around the fact that parameterized tests append "[#]" at 166596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * the end of the method names. For instance, "getFoo" would become 167596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * "getFoo[0]". 168596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root */ 169596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private static Filter matchParameterizedMethod(final Description target) { 170596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return new Filter() { 171596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root Pattern pat = Pattern.compile(target.getMethodName() + "(\\[[0-9]+\\])?"); 172596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 173596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 174596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public boolean shouldRun(Description desc) { 175596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (desc.isTest()) { 176596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return target.getClassName().equals(desc.getClassName()) 177596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root && isMatch(desc.getMethodName()); 178596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 179596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 180596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root for (Description child : desc.getChildren()) { 181596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (shouldRun(child)) { 182596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 183596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 184596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 185596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return false; 186596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 187596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 188596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private boolean isMatch(String first) { 189596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return pat.matcher(first).matches(); 190596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 191596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 192596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 193596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public String describe() { 194596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return String.format("Method %s", target.getDisplayName()); 195596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 196596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root }; 197596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 198596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 199596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /** 2005e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Run only tests with given size 2015e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * @param testSize 2025e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 2035e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public void addTestSizeFilter(String testSize) { 2049dba8dea5781124be4e0848adba21215e622052fBrett Chabot if (SMALL_SIZE.equals(testSize)) { 2055e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(SmallTest.class)); 2069dba8dea5781124be4e0848adba21215e622052fBrett Chabot } else if (MEDIUM_SIZE.equals(testSize)) { 2075e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(MediumTest.class)); 2089dba8dea5781124be4e0848adba21215e622052fBrett Chabot } else if (LARGE_SIZE.equals(testSize)) { 2095e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(LargeTest.class)); 2105e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 2115e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot Log.e(LOG_TAG, String.format("Unrecognized test size '%s'", testSize)); 2125e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2135e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2145e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 2155e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 21616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Only run tests annotated with given annotation class. 21716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 21816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param annotation the full class name of annotation 21916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 22016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationInclusionFilter(String annotation) { 22116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(annotation); 22216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 22316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(annotationClass)); 22416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 22516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 22616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 22716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 22816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Skip tests annotated with given annotation class. 22916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 23016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param notAnnotation the full class name of annotation 23116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 23216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationExclusionFilter(String notAnnotation) { 23316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(notAnnotation); 23416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 23516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationExclusionFilter(annotationClass)); 23616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 23716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 23816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 23916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 2403604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * Build a request that will generate test started and test ended events, but will skip actual 2413604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * test execution. 2423604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot */ 2433604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot public void setSkipExecution(boolean b) { 2443604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mSkipExecution = b; 2453604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot } 2463604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot 2473604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot /** 2480e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Builds the {@link TestRequest} based on current contents of added classes and methods. 2490e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 2500e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * If no classes have been explicitly added, will scan the classpath for all tests. 2510e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * 2520e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 253cebe48ef03abf67e1957a8df4574c79191a5c482Brett Chabot public TestRequest build(Instrumentation instr) { 2540e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (mTestLoader.isEmpty()) { 2550e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot // no class restrictions have been specified. Load all classes 2560e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot loadClassesFromClassPath(); 257bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 258bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 2593604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot Request request = classes(instr, mSkipExecution, new Computer(), 2603604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mTestLoader.getLoadedClasses().toArray(new Class[0])); 2610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new TestRequest(mTestLoader.getLoadFailures(), request.filterWith(mFilter)); 262bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 263bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 26453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot /** 26553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * Create a <code>Request</code> that, when processed, will run all the tests 26653196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * in a set of classes. 26753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * 26853196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param instr the {@link Instrumentation} to inject into any tests that require it 26953196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param computer Helps construct Runners from classes 27053196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param classes the classes containing the tests 27153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @return a <code>Request</code> that will cause all tests in the classes to be run 27253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot */ 2733604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot private static Request classes(Instrumentation instr, boolean skipExecution, 2743604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot Computer computer, Class<?>... classes) { 27553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot try { 2763604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot AndroidRunnerBuilder builder = new AndroidRunnerBuilder(true, instr, skipExecution); 27753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot Runner suite = computer.getSuite(builder, classes); 27853196f43b44ff02da07c243798168d7e5614ec34Brett Chabot return Request.runner(suite); 27953196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } catch (InitializationError e) { 28053196f43b44ff02da07c243798168d7e5614ec34Brett Chabot throw new RuntimeException( 28153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot "Suite constructor, called as above, should always complete"); 28253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 28353196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 28453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot 2850e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private void loadClassesFromClassPath() { 2860e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Collection<String> classNames = getClassNamesFromClassPath(); 2870e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot for (String className : classNames) { 2880e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadIfTest(className); 2890e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 2900e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 2910e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 2920e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private Collection<String> getClassNamesFromClassPath() { 293bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.i(LOG_TAG, String.format("Scanning classpath to find tests in apks %s", 294bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Arrays.toString(mApkPaths))); 295bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot ClassPathScanner scanner = new ClassPathScanner(mApkPaths); 296bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot try { 29753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot // exclude inner classes, and classes from junit and this lib namespace 298bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return scanner.getClassPathEntries(new ChainedClassNameFilter( 299bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("junit"), 300bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.junit"), 301bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.hamcrest"), 3023604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot new ExternalClassNameFilter(), 3033604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot new ExcludePackageNameFilter("com.android.test.runner.junit3"))); 304bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } catch (IOException e) { 3050e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mWriter.println("failed to scan classes"); 306bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.e(LOG_TAG, "Failed to scan classes", e); 307bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 308bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return Collections.emptyList(); 309bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 3100e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 3110e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 3120e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Factory method for {@link ClassPathScanner}. 3130e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 3140e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Exposed so unit tests can mock. 3150e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 3160e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot ClassPathScanner createClassPathScanner(String... apkPaths) { 3170e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new ClassPathScanner(apkPaths); 3180e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 31916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 32016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @SuppressWarnings("unchecked") 32116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Class<? extends Annotation> loadAnnotationClass(String className) { 32216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot try { 32316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<?> clazz = Class.forName(className); 32416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return (Class<? extends Annotation>)clazz; 32516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassNotFoundException e) { 32616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Could not find annotation class: %s", className)); 32716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassCastException e) { 32816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Class %s is not an annotation", className)); 32916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 33016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return null; 33116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 332bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot} 333