• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.platform.test.util;
17 
18 import android.os.Bundle;
19 import androidx.annotation.VisibleForTesting;
20 import androidx.test.InstrumentationRegistry;
21 
22 import java.lang.reflect.Constructor;
23 
24 import org.junit.runner.Runner;
25 import org.junit.runners.JUnit4;
26 import org.junit.runners.model.RunnerBuilder;
27 
28 /**
29  * A {@link RunnerBuilder} that enables using a specified runner to run tests in a suite.
30  *
31  * <p>Usage: When instrumenting with AndroidJUnitRunner, use
32  *
33  * <pre>-e runnerBuilder android.platform.test.longevity.HealthRunnerBuilder -e use-runner
34  * (name_of_runner)
35  *
36  * <p>The runner name can be supplied with the fully qualified class name of the runner. It also has
37  * to be a {@link Runner} class and statically included in the APK.
38  */
39 public class HealthRunnerBuilder extends RunnerBuilder {
40     @VisibleForTesting static final String RUNNER_OPTION = "use-runner";
41     // The runner class to use as specified by the option. Defaults to the JUnit4 runner.
42     private Class<?> mRunnerClass = JUnit4.class;
43 
HealthRunnerBuilder()44     public HealthRunnerBuilder() {
45         this(InstrumentationRegistry.getArguments());
46     }
47 
48     @VisibleForTesting
HealthRunnerBuilder(Bundle args)49     HealthRunnerBuilder(Bundle args) {
50         String runnerName = args.getString(RUNNER_OPTION);
51         if (runnerName != null) {
52             Class<?> loadedClass = null;
53             try {
54                 loadedClass = HealthRunnerBuilder.class.getClassLoader().loadClass(runnerName);
55             } catch (ClassNotFoundException e) {
56                 throw new RuntimeException(
57                         String.format(
58                                 "Could not find class with fully qualified name %s.", runnerName));
59             }
60             // Ensure that the class found is a Runner.
61             if (loadedClass != null && Runner.class.isAssignableFrom(loadedClass)) {
62                 mRunnerClass = loadedClass;
63             } else {
64                 throw new RuntimeException(String.format("Class %s is not a runner.", loadedClass));
65             }
66         }
67     }
68 
69     @Override
runnerForClass(Class<?> testClass)70     public Runner runnerForClass(Class<?> testClass) throws Throwable {
71         try {
72             Constructor<?> runnerConstructor = mRunnerClass.getConstructor(Class.class);
73             // Cast is safe as getRunnerClass() ensures that instantiations of its return type are
74             // subclasses of Runner.
75             return (Runner) runnerConstructor.newInstance(testClass);
76         } catch (NoSuchMethodException e) {
77             throw new RuntimeException(
78                     String.format(
79                             "Runner %s cannot be instantiated with the test class alone.",
80                             mRunnerClass),
81                     e);
82         } catch (SecurityException e) {
83             throw new RuntimeException(e);
84         }
85     }
86 }
87