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; 29bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 3053196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Computer; 310e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabotimport org.junit.runner.Description; 32bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.Request; 3353196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runner.Runner; 34bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport org.junit.runner.manipulation.Filter; 3553196f43b44ff02da07c243798168d7e5614ec34Brett Chabotimport org.junit.runners.model.InitializationError; 36bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 37bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.IOException; 38bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.io.PrintStream; 395e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabotimport java.lang.annotation.Annotation; 40bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Arrays; 41bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collection; 42bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotimport java.util.Collections; 43596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Rootimport java.util.regex.Pattern; 44bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 45bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot/** 46bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * Builds a {@link Request} from test classes in given apk paths, filtered on provided set of 47bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * restrictions. 48bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 49bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabotpublic class TestRequestBuilder { 50bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 51bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private static final String LOG_TAG = "TestRequestBuilder"; 52bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 53f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String LARGE_SIZE = "large"; 54f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String MEDIUM_SIZE = "medium"; 55f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot public static final String SMALL_SIZE = "small"; 56f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot 57bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot private String[] mApkPaths; 580e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private TestLoader mTestLoader; 5916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Filter mFilter = new AnnotationExclusionFilter(Suppress.class); 600e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private PrintStream mWriter; 613604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot private boolean mSkipExecution = false; 620e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 635e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 645e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Filter that only runs tests whose method or class has been annotated with given filter. 655e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 665e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private static class AnnotationInclusionFilter extends Filter { 675e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 685e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 695e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 705e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot AnnotationInclusionFilter(Class<? extends Annotation> annotation) { 715e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mAnnotationClass = annotation; 725e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 735e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 745e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 755e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 765e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 775e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 785e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public boolean shouldRun(Description description) { 795e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot if (description.isTest()) { 805e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return description.getAnnotation(mAnnotationClass) != null || 815e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot description.getTestClass().isAnnotationPresent(mAnnotationClass); 825e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 834c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // the entire test class/suite should be filtered out if all its methods are 844c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // filtered 854c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // TODO: This is not efficient since some children may end up being evaluated more 864c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // than once. This logic seems to be only necessary for JUnit3 tests. Look into 874c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // fixing in upstream 884c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot for (Description child : description.getChildren()) { 894c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot if (shouldRun(child)) { 904c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot return true; 914c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot } 924c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot } 934c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot // no children to run, filter this out 944c88c2100e947576671cea794fca1f4fe3dc52f5Brett Chabot return false; 955e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 965e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 975e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 985e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 995e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * {@inheritDoc} 1005e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 1015e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot @Override 1025e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public String describe() { 1035e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot return String.format("annotation %s", mAnnotationClass.getName()); 1045e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 1055e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 1065e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 10716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 10816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Filter out tests whose method or class has been annotated with given filter. 10916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 11016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private static class AnnotationExclusionFilter extends Filter { 11116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 11216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private final Class<? extends Annotation> mAnnotationClass; 11316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 11416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot AnnotationExclusionFilter(Class<? extends Annotation> annotation) { 11516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mAnnotationClass = annotation; 11616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 11716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 11816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 11916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 12016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 12116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 12216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public boolean shouldRun(Description description) { 123596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root final Class<?> testClass = description.getTestClass(); 124596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 125596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /* Parameterized tests have no test classes. */ 126596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass == null) { 127596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 128596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 129596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 130596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (testClass.isAnnotationPresent(mAnnotationClass) || 13116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot description.getAnnotation(mAnnotationClass) != null) { 13216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return false; 13316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } else { 13416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return true; 13516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 13716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 13816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 13916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * {@inheritDoc} 14016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 14116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @Override 14216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public String describe() { 14316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return String.format("not annotation %s", mAnnotationClass.getName()); 14416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 14516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 14616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 1470e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public TestRequestBuilder(PrintStream writer, String... apkPaths) { 148bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot mApkPaths = apkPaths; 1490e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader = new TestLoader(writer); 150bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 151bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 152bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot /** 1530e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Add a test class to be executed. All test methods in this class will be executed. 154bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot * 1550e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * @param className 156bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot */ 157bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot public void addTestClass(String className) { 1580e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadClass(className); 159bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 160bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 1610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 1620e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Adds a test method to run. 1630e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 1640e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Currently only supports one test method to be run. 1650e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 1660e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot public void addTestMethod(String testClassName, String testMethodName) { 1670e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Class<?> clazz = mTestLoader.loadClass(testClassName); 1680e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (clazz != null) { 169596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root mFilter = mFilter.intersect(matchParameterizedMethod( 1700e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Description.createTestDescription(clazz, testMethodName))); 1710e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1720e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 1730e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 1740e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 175596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * A filter to get around the fact that parameterized tests append "[#]" at 176596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * the end of the method names. For instance, "getFoo" would become 177596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root * "getFoo[0]". 178596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root */ 179596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private static Filter matchParameterizedMethod(final Description target) { 180596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return new Filter() { 181596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root Pattern pat = Pattern.compile(target.getMethodName() + "(\\[[0-9]+\\])?"); 182596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 183596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 184596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public boolean shouldRun(Description desc) { 185596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (desc.isTest()) { 186596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return target.getClassName().equals(desc.getClassName()) 187596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root && isMatch(desc.getMethodName()); 188596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 189596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 190596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root for (Description child : desc.getChildren()) { 191596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root if (shouldRun(child)) { 192596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return true; 193596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 194596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 195596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return false; 196596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 197596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 198596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root private boolean isMatch(String first) { 199596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return pat.matcher(first).matches(); 200596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 201596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 202596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root @Override 203596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root public String describe() { 204596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root return String.format("Method %s", target.getDisplayName()); 205596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 206596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root }; 207596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root } 208596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root 209596c213fe3d9b8035ceb868b23cebc39dc2a3636Kenny Root /** 2105e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * Run only tests with given size 2115e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot * @param testSize 2125e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot */ 2135e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot public void addTestSizeFilter(String testSize) { 214f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot if (SMALL_SIZE.equals(testSize)) { 2155e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(SmallTest.class)); 216f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot } else if (MEDIUM_SIZE.equals(testSize)) { 2175e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(MediumTest.class)); 218f1b61e2846c7475a54472f6f82adaea231a35b0cBrett Chabot } else if (LARGE_SIZE.equals(testSize)) { 2195e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(LargeTest.class)); 2205e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } else { 2215e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot Log.e(LOG_TAG, String.format("Unrecognized test size '%s'", testSize)); 2225e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2235e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot } 2245e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot 2255e6ca275201fea0fd0316fb15bc7d0248e224b2cBrett Chabot /** 22616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Only run tests annotated with given annotation class. 22716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 22816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param annotation the full class name of annotation 22916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 23016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationInclusionFilter(String annotation) { 23116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(annotation); 23216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 23316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationInclusionFilter(annotationClass)); 23416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 23516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 23616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 23716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 23816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * Skip tests annotated with given annotation class. 23916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * 24016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot * @param notAnnotation the full class name of annotation 24116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot */ 24216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot public void addAnnotationExclusionFilter(String notAnnotation) { 24316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<? extends Annotation> annotationClass = loadAnnotationClass(notAnnotation); 24416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot if (annotationClass != null) { 24516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot mFilter = mFilter.intersect(new AnnotationExclusionFilter(annotationClass)); 24616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 24716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 24816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 24916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot /** 2503604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * Build a request that will generate test started and test ended events, but will skip actual 2513604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot * test execution. 2523604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot */ 2533604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot public void setSkipExecution(boolean b) { 2543604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mSkipExecution = b; 2553604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot } 2563604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot 2573604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot /** 2580e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Builds the {@link TestRequest} based on current contents of added classes and methods. 2590e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 2600e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * If no classes have been explicitly added, will scan the classpath for all tests. 2610e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * 2620e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 263fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot public TestRequest build(Instrumentation instr, Bundle bundle) { 2640e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot if (mTestLoader.isEmpty()) { 2650e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot // no class restrictions have been specified. Load all classes 2660e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot loadClassesFromClassPath(); 267bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 268bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 269fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot Request request = classes(instr, bundle, mSkipExecution, new Computer(), 2703604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot mTestLoader.getLoadedClasses().toArray(new Class[0])); 2710e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new TestRequest(mTestLoader.getLoadFailures(), request.filterWith(mFilter)); 272bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 273bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot 27453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot /** 27553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * Create a <code>Request</code> that, when processed, will run all the tests 27653196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * in a set of classes. 27753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * 27853196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param instr the {@link Instrumentation} to inject into any tests that require it 279fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot * @param bundle the {@link Bundle} of command line args to inject into any tests that require 280fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot * it 28153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param computer Helps construct Runners from classes 28253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @param classes the classes containing the tests 28353196f43b44ff02da07c243798168d7e5614ec34Brett Chabot * @return a <code>Request</code> that will cause all tests in the classes to be run 28453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot */ 285fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot private static Request classes(Instrumentation instr, Bundle bundle, boolean skipExecution, 2863604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot Computer computer, Class<?>... classes) { 28753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot try { 288fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot AndroidRunnerBuilder builder = new AndroidRunnerBuilder(true, instr, bundle, 289fc37a0172db7197e6e0702dfa9bfdd6bed1947b1Brett Chabot skipExecution); 29053196f43b44ff02da07c243798168d7e5614ec34Brett Chabot Runner suite = computer.getSuite(builder, classes); 29153196f43b44ff02da07c243798168d7e5614ec34Brett Chabot return Request.runner(suite); 29253196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } catch (InitializationError e) { 29353196f43b44ff02da07c243798168d7e5614ec34Brett Chabot throw new RuntimeException( 29453196f43b44ff02da07c243798168d7e5614ec34Brett Chabot "Suite constructor, called as above, should always complete"); 29553196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 29653196f43b44ff02da07c243798168d7e5614ec34Brett Chabot } 29753196f43b44ff02da07c243798168d7e5614ec34Brett Chabot 2980e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private void loadClassesFromClassPath() { 2990e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot Collection<String> classNames = getClassNamesFromClassPath(); 3000e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot for (String className : classNames) { 3010e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mTestLoader.loadIfTest(className); 3020e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 3030e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 3040e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 3050e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot private Collection<String> getClassNamesFromClassPath() { 306bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.i(LOG_TAG, String.format("Scanning classpath to find tests in apks %s", 307bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Arrays.toString(mApkPaths))); 308bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot ClassPathScanner scanner = new ClassPathScanner(mApkPaths); 309bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot try { 31053196f43b44ff02da07c243798168d7e5614ec34Brett Chabot // exclude inner classes, and classes from junit and this lib namespace 311bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return scanner.getClassPathEntries(new ChainedClassNameFilter( 312bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("junit"), 313bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.junit"), 314bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot new ExcludePackageNameFilter("org.hamcrest"), 31502693f872930994fffc46c600927cac3a2f82e6dBrett Chabot new ExcludePackageNameFilter("org.mockito"), 31602693f872930994fffc46c600927cac3a2f82e6dBrett Chabot new ExcludePackageNameFilter("com.android.dx"), 31702693f872930994fffc46c600927cac3a2f82e6dBrett Chabot new ExcludePackageNameFilter("com.google.dexmaker"), 3183604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot new ExternalClassNameFilter(), 3193604db5bcd124dfd1396fb51434d3f4337690cffBrett Chabot new ExcludePackageNameFilter("com.android.test.runner.junit3"))); 320bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } catch (IOException e) { 3210e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot mWriter.println("failed to scan classes"); 322bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot Log.e(LOG_TAG, "Failed to scan classes", e); 323bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 324bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot return Collections.emptyList(); 325bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot } 3260e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot 3270e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot /** 3280e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Factory method for {@link ClassPathScanner}. 3290e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * <p/> 3300e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot * Exposed so unit tests can mock. 3310e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot */ 3320e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot ClassPathScanner createClassPathScanner(String... apkPaths) { 3330e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot return new ClassPathScanner(apkPaths); 3340e1d66fcd74344182e3bfca913744b1a66e7a188Brett Chabot } 33516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot 33616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot @SuppressWarnings("unchecked") 33716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot private Class<? extends Annotation> loadAnnotationClass(String className) { 33816522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot try { 33916522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Class<?> clazz = Class.forName(className); 34016522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return (Class<? extends Annotation>)clazz; 34116522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassNotFoundException e) { 34216522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Could not find annotation class: %s", className)); 34316522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } catch (ClassCastException e) { 34416522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot Log.e(LOG_TAG, String.format("Class %s is not an annotation", className)); 34516522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 34616522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot return null; 34716522ab7fbaaa627c2c51cfc1339c2248af6df1bBrett Chabot } 348bb23e68d4dc19a37df318b8d169e3dfd0dd1c20eBrett Chabot} 349