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; 19fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabotimport android.os.Bundle; 205e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.LargeTest; 215e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.MediumTest; 225e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport android.test.suitebuilder.annotation.SmallTest; 2316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabotimport android.test.suitebuilder.annotation.Suppress; 24bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport android.util.Log; 25bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 26bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ChainedClassNameFilter; 27bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ExcludePackageNameFilter; 28bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport com.android.test.runner.ClassPathScanner.ExternalClassNameFilter; 29442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabotimport com.android.test.runner.ClassPathScanner.InclusivePackageNameFilter; 30bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 3153196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Computer; 320e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabotimport org.junit.runner.Description; 33bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.Request; 3453196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Runner; 35bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.manipulation.Filter; 3653196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runners.model.InitializationError; 37bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 38bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.IOException; 39bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.PrintStream; 405e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport java.lang.annotation.Annotation; 41bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Arrays; 42bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collection; 43bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collections; 44596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Rootimport java.util.regex.Pattern; 45bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 46bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/** 47bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Builds a {@link Request} from test classes in given apk paths, filtered on provided set of 48bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * restrictions. 49bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 50bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotpublic class TestRequestBuilder { 51bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 52bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private static final String LOG_TAG = "TestRequestBuilder"; 53bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 54f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String LARGE_SIZE = "large"; 55f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String MEDIUM_SIZE = "medium"; 56f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String SMALL_SIZE = "small"; 57f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot 58bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private String[] mApkPaths; 590e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private TestLoader mTestLoader; 6016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Filter mFilter = new AnnotationExclusionFilter(Suppress.class); 610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private PrintStream mWriter; 623604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot private boolean mSkipExecution = false; 63442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot private String mTestPackageName = null; 640e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 655e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 665e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Filter that only runs tests whose method or class has been annotated with given filter. 675e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 685e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private static class AnnotationInclusionFilter extends Filter { 695e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 705e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 715e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 725e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot AnnotationInclusionFilter(Class<? extends Annotation> annotation) { 735e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mAnnotationClass = annotation; 745e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 755e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 765e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 775e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 785e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 795e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 805e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public boolean shouldRun(Description description) { 815e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot if (description.isTest()) { 825e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return description.getAnnotation(mAnnotationClass) != null || 835e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot description.getTestClass().isAnnotationPresent(mAnnotationClass); 845e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 854c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // the entire test class/suite should be filtered out if all its methods are 864c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // filtered 874c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // TODO: This is not efficient since some children may end up being evaluated more 884c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // than once. This logic seems to be only necessary for JUnit3 tests. Look into 894c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // fixing in upstream 904c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot for (Description child : description.getChildren()) { 914c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot if (shouldRun(child)) { 924c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot return true; 934c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot } 944c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot } 954c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // no children to run, filter this out 964c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot return false; 975e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 985e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 995e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 1005e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 1015e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 1025e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 1035e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 1045e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public String describe() { 1055e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return String.format("annotation %s", mAnnotationClass.getName()); 1065e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 1075e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 1085e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 10916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 11016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Filter out tests whose method or class has been annotated with given filter. 11116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 11216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private static class AnnotationExclusionFilter extends Filter { 11316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 11416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 11516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 11616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot AnnotationExclusionFilter(Class<? extends Annotation> annotation) { 11716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mAnnotationClass = annotation; 11816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 11916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 12016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 12116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 12216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 12316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 12416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public boolean shouldRun(Description description) { 125596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root final Class<?> testClass = description.getTestClass(); 126596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 127596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /* Parameterized tests have no test classes. */ 128596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass == null) { 129596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 130596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 131596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 132596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass.isAnnotationPresent(mAnnotationClass) || 13316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot description.getAnnotation(mAnnotationClass) != null) { 13416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return false; 13516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } else { 13616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return true; 13716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 14016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 14116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 14216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 14316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 14416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public String describe() { 14516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return String.format("not annotation %s", mAnnotationClass.getName()); 14616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 14716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 14816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 1490e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public TestRequestBuilder(PrintStream writer, String... apkPaths) { 150bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mApkPaths = apkPaths; 1510e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader = new TestLoader(writer); 152bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 153bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 154bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 1550e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Add a test class to be executed. All test methods in this class will be executed. 156bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 1570e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * @param className 158bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 159bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public void addTestClass(String className) { 1600e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadClass(className); 161bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 162bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 1630e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 1640e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Adds a test method to run. 1650e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 1660e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Currently only supports one test method to be run. 1670e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 1680e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public void addTestMethod(String testClassName, String testMethodName) { 1690e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Class<?> clazz = mTestLoader.loadClass(testClassName); 1700e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (clazz != null) { 171596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root mFilter = mFilter.intersect(matchParameterizedMethod( 1720e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Description.createTestDescription(clazz, testMethodName))); 1730e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1740e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1750e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 1760e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 177596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * A filter to get around the fact that parameterized tests append "[#]" at 178596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * the end of the method names. For instance, "getFoo" would become 179596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * "getFoo[0]". 180596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root */ 181596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private static Filter matchParameterizedMethod(final Description target) { 182596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return new Filter() { 183596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root Pattern pat = Pattern.compile(target.getMethodName() + "(\\[[0-9]+\\])?"); 184596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 185596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 186596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public boolean shouldRun(Description desc) { 187596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (desc.isTest()) { 188596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return target.getClassName().equals(desc.getClassName()) 189596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root && isMatch(desc.getMethodName()); 190596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 191596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 192596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root for (Description child : desc.getChildren()) { 193596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (shouldRun(child)) { 194596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 195596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 196596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 197596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return false; 198596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 199596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 200596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private boolean isMatch(String first) { 201596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return pat.matcher(first).matches(); 202596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 203596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 204596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 205596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public String describe() { 206596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return String.format("Method %s", target.getDisplayName()); 207596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 208596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root }; 209596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 210596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 211596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /** 212442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot * Run only tests within given java package 213442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot * @param testPackage 214442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot */ 215442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot public void addTestPackageFilter(String testPackage) { 216442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot mTestPackageName = testPackage; 217442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot } 218442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot 219442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot /** 2205e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Run only tests with given size 2215e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * @param testSize 2225e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 2235e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public void addTestSizeFilter(String testSize) { 224f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot if (SMALL_SIZE.equals(testSize)) { 2255e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(SmallTest.class)); 226f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot } else if (MEDIUM_SIZE.equals(testSize)) { 2275e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(MediumTest.class)); 228f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot } else if (LARGE_SIZE.equals(testSize)) { 2295e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(LargeTest.class)); 2305e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 2315e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot Log.e(LOG_TAG, String.format("Unrecognized test size '%s'", testSize)); 2325e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2335e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2345e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 2355e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 23616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Only run tests annotated with given annotation class. 23716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 23816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param annotation the full class name of annotation 23916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 24016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationInclusionFilter(String annotation) { 24116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(annotation); 24216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 24316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(annotationClass)); 24416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 24516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 24616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 24716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 24816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Skip tests annotated with given annotation class. 24916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 25016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param notAnnotation the full class name of annotation 25116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 25216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationExclusionFilter(String notAnnotation) { 25316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(notAnnotation); 25416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 25516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationExclusionFilter(annotationClass)); 25616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 25716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 25816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 25916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 2603604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * Build a request that will generate test started and test ended events, but will skip actual 2613604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * test execution. 2623604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot */ 2633604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot public void setSkipExecution(boolean b) { 2643604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mSkipExecution = b; 2653604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot } 2663604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot 2673604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot /** 2680e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Builds the {@link TestRequest} based on current contents of added classes and methods. 2690e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 2700e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * If no classes have been explicitly added, will scan the classpath for all tests. 2710e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * 2720e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 273fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot public TestRequest build(Instrumentation instr, Bundle bundle) { 2740e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (mTestLoader.isEmpty()) { 2750e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot // no class restrictions have been specified. Load all classes 2760e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot loadClassesFromClassPath(); 277bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 278bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 279fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot Request request = classes(instr, bundle, mSkipExecution, new Computer(), 2803604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mTestLoader.getLoadedClasses().toArray(new Class[0])); 2810e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new TestRequest(mTestLoader.getLoadFailures(), request.filterWith(mFilter)); 282bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 283bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 28453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot /** 28553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * Create a <code>Request</code> that, when processed, will run all the tests 28653196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * in a set of classes. 28753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * 28853196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param instr the {@link Instrumentation} to inject into any tests that require it 289fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot * @param bundle the {@link Bundle} of command line args to inject into any tests that require 290fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot * it 29153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param computer Helps construct Runners from classes 29253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param classes the classes containing the tests 29353196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @return a <code>Request</code> that will cause all tests in the classes to be run 29453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot */ 295fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot private static Request classes(Instrumentation instr, Bundle bundle, boolean skipExecution, 2963604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot Computer computer, Class<?>... classes) { 29753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot try { 298fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot AndroidRunnerBuilder builder = new AndroidRunnerBuilder(true, instr, bundle, 299fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot skipExecution); 30053196f43b44ff02da07c243798168d7e5614ec34Brett Chabot Runner suite = computer.getSuite(builder, classes); 30153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot return Request.runner(suite); 30253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } catch (InitializationError e) { 30353196f43b44ff02da07c243798168d7e5614ec34Brett Chabot throw new RuntimeException( 30453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot "Suite constructor, called as above, should always complete"); 30553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 30653196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 30753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot 3080e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private void loadClassesFromClassPath() { 3090e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Collection<String> classNames = getClassNamesFromClassPath(); 3100e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot for (String className : classNames) { 3110e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadIfTest(className); 3120e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 3130e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 3140e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 3150e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private Collection<String> getClassNamesFromClassPath() { 316bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.i(LOG_TAG, String.format("Scanning classpath to find tests in apks %s", 317bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Arrays.toString(mApkPaths))); 318bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot ClassPathScanner scanner = new ClassPathScanner(mApkPaths); 319442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot 320442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot ChainedClassNameFilter filter = new ChainedClassNameFilter(); 321442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot // exclude inner classes 322442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot filter.add(new ExternalClassNameFilter()); 323442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot if (mTestPackageName != null) { 324442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot // request to run only a specific java package, honor that 325442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot filter.add(new InclusivePackageNameFilter(mTestPackageName)); 326442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot } else { 327442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot // scan all packages, but exclude junit packages 328442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot filter.addAll(new ExcludePackageNameFilter("junit"), 329bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.junit"), 330bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.hamcrest"), 331442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot new ExcludePackageNameFilter("com.android.test.runner.junit3")); 332442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot } 333442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot 334442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot try { 335442abfa0f3e4ef244665ec20082c50d5cc6d4149Brett Chabot return scanner.getClassPathEntries(filter); 336bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } catch (IOException e) { 3370e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mWriter.println("failed to scan classes"); 338bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.e(LOG_TAG, "Failed to scan classes", e); 339bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 340bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return Collections.emptyList(); 341bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 3420e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 3430e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 3440e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Factory method for {@link ClassPathScanner}. 3450e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 3460e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Exposed so unit tests can mock. 3470e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 3480e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot ClassPathScanner createClassPathScanner(String... apkPaths) { 3490e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new ClassPathScanner(apkPaths); 3500e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 35116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 35216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @SuppressWarnings("unchecked") 35316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Class<? extends Annotation> loadAnnotationClass(String className) { 35416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot try { 35516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<?> clazz = Class.forName(className); 35616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return (Class<? extends Annotation>)clazz; 35716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassNotFoundException e) { 35816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Could not find annotation class: %s", className)); 35916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassCastException e) { 36016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Class %s is not an annotation", className)); 36116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 36216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return null; 36316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 364bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot} 365