TestRequestBuilder.java revision e514756957cb44d88ceab42c53ef321e76e1368b
14b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/*
24b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Copyright (C) 2012 The Android Open Source Project
34b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
44b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
54b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * you may not use this file except in compliance with the License.
64b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * You may obtain a copy of the License at
74b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
84b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
94b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov *
104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software
114b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
124b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * See the License for the specific language governing permissions and
144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov * limitations under the License.
154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovpackage com.android.test.runner;
174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.app.Instrumentation;
194b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.os.Bundle;
20d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.test.suitebuilder.annotation.LargeTest;
21d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.test.suitebuilder.annotation.MediumTest;
22d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport android.test.suitebuilder.annotation.SmallTest;
234b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.test.suitebuilder.annotation.Suppress;
244b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport android.util.Log;
254b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport com.android.test.runner.ClassPathScanner.ChainedClassNameFilter;
274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport com.android.test.runner.ClassPathScanner.ExcludePackageNameFilter;
284b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport com.android.test.runner.ClassPathScanner.ExternalClassNameFilter;
29d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
30d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslavimport org.junit.runner.Computer;
314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport org.junit.runner.Description;
324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport org.junit.runner.Request;
334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport org.junit.runner.Runner;
347bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavimport org.junit.runner.manipulation.Filter;
354b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport org.junit.runners.model.InitializationError;
36704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganov
374b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.io.IOException;
38a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganovimport java.io.PrintStream;
39704697b6197262678e930daa831a1916ddee4dcfSvetoslav Ganovimport java.lang.annotation.Annotation;
404b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Arrays;
4144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganovimport java.util.Collection;
424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganovimport java.util.Collections;
432fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
444b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov/**
4544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov * Builds a {@link Request} from test classes in given apk paths, filtered on provided set of
46860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov * restrictions.
474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov */
487bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslavpublic class TestRequestBuilder {
49a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private static final String LOG_TAG = "TestRequestBuilder";
51d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
524b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String LARGE_SIZE = "large";
53a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public static final String MEDIUM_SIZE = "medium";
544b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public static final String SMALL_SIZE = "small";
55b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov
56b669917825a49421ee79be4819ead765f5de8aaeSvetoslav Ganov    private String[] mApkPaths;
574b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private TestLoader mTestLoader;
584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private Filter mFilter = new AnnotationExclusionFilter(Suppress.class);
594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private PrintStream mWriter;
604b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    private boolean mSkipExecution = false;
614b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
624b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
634b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Filter that only runs tests whose method or class has been annotated with given filter.
644b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
65d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav    private static class AnnotationInclusionFilter extends Filter {
66d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav
67d8f391b4e0e8d876ec7216d34f86a9b3e8bab7e5Svetoslav        private final Class<? extends Annotation> mAnnotationClass;
684b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
694b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        AnnotationInclusionFilter(Class<? extends Annotation> annotation) {
704b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mAnnotationClass = annotation;
714b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
72a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
734b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        /**
744b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov         * {@inheritDoc}
754b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov         */
764b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        @Override
774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        public boolean shouldRun(Description description) {
784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (description.isTest()) {
79a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return description.getAnnotation(mAnnotationClass) != null ||
80a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                        description.getTestClass().isAnnotationPresent(mAnnotationClass);
81a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            } else {
82a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // don't filter out any test classes/suites, because their methods may have correct
83a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                // annotation
84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                return true;
85a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            }
862fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
87a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
882fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        /**
89a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov         * {@inheritDoc}
90a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov         */
912fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        @Override
922fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        public String describe() {
932fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            return String.format("annotation %s", mAnnotationClass.getName());
942fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
95a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
96a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
974b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    /**
984b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Filter out tests whose method or class has been annotated with given filter.
994b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1007bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav    private static class AnnotationExclusionFilter extends Filter {
1017bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav
102a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        private final Class<? extends Annotation> mAnnotationClass;
103a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
1047bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        AnnotationExclusionFilter(Class<? extends Annotation> annotation) {
105a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mAnnotationClass = annotation;
106a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
107a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
108a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        /**
1094b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov         * {@inheritDoc}
1104b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov         */
1117bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        @Override
1127bfbbcb04bf4ba8f3069b2df136f708c9849bacfSvetoslav        public boolean shouldRun(Description description) {
1134b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            if (description.getTestClass().isAnnotationPresent(mAnnotationClass) ||
1144b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                    description.getAnnotation(mAnnotationClass) != null) {
1154b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                return false;
1164b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            } else {
1174b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov                return true;
1184b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            }
119a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
120a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
121a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        /**
122a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov         * {@inheritDoc}
123a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov         */
124a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        @Override
125a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        public String describe() {
1264b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            return String.format("not annotation %s", mAnnotationClass.getName());
1274b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        }
1282fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    }
1294b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1304b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public TestRequestBuilder(PrintStream writer, String... apkPaths) {
1314b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mApkPaths = apkPaths;
1324b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        mTestLoader = new TestLoader(writer);
1334b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1344b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1352fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    /**
136a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * Add a test class to be executed. All test methods in this class will be executed.
137a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     *
138a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     * @param className
139a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov     */
140a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    public void addTestClass(String className) {
141a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        mTestLoader.loadClass(className);
1424b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    }
1434b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov
1442fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav    /**
1454b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Adds a test method to run.
1464b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * <p/>
1474b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Currently only supports one test method to be run.
1484b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1494b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public void addTestMethod(String testClassName, String testMethodName) {
1504b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        Class<?> clazz = mTestLoader.loadClass(testClassName);
1512fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        if (clazz != null) {
152a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov            mFilter = mFilter.intersect(Filter.matchMethodDescription(
153a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov                    Description.createTestDescription(clazz, testMethodName)));
154a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov        }
155a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    }
156a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov
157a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov    /**
1584b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * Run only tests with given size
1594b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     * @param testSize
1602fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav     */
1618c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    public void addTestSizeFilter(String testSize) {
1628c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        if (SMALL_SIZE.equals(testSize)) {
1638c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            mFilter = mFilter.intersect(new AnnotationInclusionFilter(SmallTest.class));
1648c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        } else if (MEDIUM_SIZE.equals(testSize)) {
1658c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            mFilter = mFilter.intersect(new AnnotationInclusionFilter(MediumTest.class));
1668c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        } else if (LARGE_SIZE.equals(testSize)) {
1672fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav            mFilter = mFilter.intersect(new AnnotationInclusionFilter(LargeTest.class));
1688c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov        } else {
1698c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov            Log.e(LOG_TAG, String.format("Unrecognized test size '%s'", testSize));
1702fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav        }
1718c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    }
1722fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav
1738c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov    /**
1748c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov     * Only run tests annotated with given annotation class.
1758c43376ea83a67414bd6823a472b76d41160239eSvetoslav Ganov     *
1762fbd2a7f070f246ddafd9de94efa9a98861e9136Svetoslav     * @param annotation the full class name of annotation
1774b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov     */
1784b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov    public void addAnnotationInclusionFilter(String annotation) {
1794b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        Class<? extends Annotation> annotationClass = loadAnnotationClass(annotation);
1804b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov        if (annotationClass != null) {
1814b9a4d16872bbb50712e007b419ac0b35ff1582dSvetoslav Ganov            mFilter = mFilter.intersect(new AnnotationInclusionFilter(annotationClass));
182860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        }
183860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    }
184860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov
185860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    /**
186860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * Skip tests annotated with given annotation class.
187860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     *
188860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     * @param notAnnotation the full class name of annotation
189860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov     */
190860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    public void addAnnotationExclusionFilter(String notAnnotation) {
191860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        Class<? extends Annotation> annotationClass = loadAnnotationClass(notAnnotation);
192860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        if (annotationClass != null) {
193860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov            mFilter = mFilter.intersect(new AnnotationExclusionFilter(annotationClass));
194860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov        }
195860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov    }
196860f8a6b663ca96d30d17da09eca8caf065aae62Svetoslav Ganov
19744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    /**
198d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     * Build a request that will generate test started and test ended events, but will skip actual
199d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     * test execution.
200d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     */
201d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    public void setSkipExecution(boolean b) {
202d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        mSkipExecution = b;
203d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    }
204d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav
205d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    /**
206d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     * Builds the {@link TestRequest} based on current contents of added classes and methods.
207d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     * <p/>
208d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     * If no classes have been explicitly added, will scan the classpath for all tests.
209d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     *
210d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav     */
211d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav    public TestRequest build(Instrumentation instr, Bundle bundle) {
212d8dbc13b47bec3248a86a505a30af9d0474240dcSvetoslav        if (mTestLoader.isEmpty()) {
21344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // no class restrictions have been specified. Load all classes
21444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            loadClassesFromClassPath();
21544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
21644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
21744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        Request request = classes(instr, bundle, mSkipExecution, new Computer(),
21844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                mTestLoader.getLoadedClasses().toArray(new Class[0]));
21944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return new TestRequest(mTestLoader.getLoadFailures(), request.filterWith(mFilter));
22044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
22144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
22244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    /**
22344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * Create a <code>Request</code> that, when processed, will run all the tests
22444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * in a set of classes.
22544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     *
22644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * @param instr the {@link Instrumentation} to inject into any tests that require it
22744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * @param bundle the {@link Bundle} of command line args to inject into any tests that require
22844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     *         it
22944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * @param computer Helps construct Runners from classes
23044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * @param classes the classes containing the tests
23144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * @return a <code>Request</code> that will cause all tests in the classes to be run
23244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     */
23344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private static Request classes(Instrumentation instr, Bundle bundle, boolean skipExecution,
23444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Computer computer, Class<?>... classes) {
23544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
23644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            AndroidRunnerBuilder builder = new AndroidRunnerBuilder(true, instr, bundle,
23744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    skipExecution);
23844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Runner suite = computer.getSuite(builder, classes);
23944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return Request.runner(suite);
24044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (InitializationError e) {
24144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            throw new RuntimeException(
24244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    "Suite constructor, called as above, should always complete");
24344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
24444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
24544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
24644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private void loadClassesFromClassPath() {
24744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        Collection<String> classNames = getClassNamesFromClassPath();
24844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        for (String className : classNames) {
24944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mTestLoader.loadIfTest(className);
25044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
25144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
25244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
25344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private Collection<String> getClassNamesFromClassPath() {
25444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        Log.i(LOG_TAG, String.format("Scanning classpath to find tests in apks %s",
25544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                Arrays.toString(mApkPaths)));
25644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        ClassPathScanner scanner = new ClassPathScanner(mApkPaths);
25744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
25844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            // exclude inner classes, and classes from junit and this lib namespace
25944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            return scanner.getClassPathEntries(new ChainedClassNameFilter(
26044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    new ExcludePackageNameFilter("junit"),
26144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    new ExcludePackageNameFilter("org.junit"),
26244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    new ExcludePackageNameFilter("org.hamcrest"),
26344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    new ExternalClassNameFilter(),
26444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov                    new ExcludePackageNameFilter("com.android.test.runner.junit3")));
26544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        } catch (IOException e) {
26644720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            mWriter.println("failed to scan classes");
26744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov            Log.e(LOG_TAG, "Failed to scan classes", e);
26844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        }
26944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return Collections.emptyList();
27044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
27144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
27244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    /**
27344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * Factory method for {@link ClassPathScanner}.
27444720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * <p/>
27544720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov     * Exposed so unit tests can mock.
276d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov     */
27744720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    ClassPathScanner createClassPathScanner(String... apkPaths) {
27844720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        return new ClassPathScanner(apkPaths);
27944720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    }
28044720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov
28144720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    @SuppressWarnings("unchecked")
28244720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov    private Class<? extends Annotation> loadAnnotationClass(String className) {
28344720af55a8fdf991929983dad5d53c02851dd1eSvetoslav Ganov        try {
284d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Class<?> clazz = Class.forName(className);
285d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            return (Class<? extends Annotation>)clazz;
286d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (ClassNotFoundException e) {
287d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, String.format("Could not find annotation class: %s", className));
288d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        } catch (ClassCastException e) {
289d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov            Log.e(LOG_TAG, String.format("Class %s is not an annotation", className));
290d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        }
291d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov        return null;
292d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov    }
293d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov}
294d26d4898fcc9b78f4b66118895c375384098205eSvetoslav Ganov