• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package android.platform.longevity;
2 
3 import android.os.Bundle;
4 import android.platform.longevity.listeners.BatteryTerminator;
5 import android.platform.longevity.listeners.ErrorTerminator;
6 import android.platform.longevity.listeners.TimeoutTerminator;
7 import android.platform.longevity.scheduler.Iterate;
8 import android.platform.longevity.scheduler.Shuffle;
9 import android.support.annotation.VisibleForTesting;
10 import android.support.test.InstrumentationRegistry;
11 
12 import java.util.List;
13 import java.util.function.BiFunction;
14 
15 import org.junit.runner.Runner;
16 import org.junit.runners.Suite;
17 import org.junit.runners.model.InitializationError;
18 import org.junit.runners.model.RunnerBuilder;
19 import org.junit.runner.notification.RunNotifier;
20 
21 /**
22  * Using the {@code LongevitySuite} as a runner allows you to run test sequences repeatedly and with
23  * shuffling in order to simulate longevity conditions and repeated stress or exercise. For examples
24  * look at the bundled sample package.
25  *
26  * TODO(b/62445871): Provide external documentation.
27  */
28 public final class LongevitySuite<T> extends Suite {
29     private static final String QUITTER_OPTION = "quitter";
30     private static final String QUITTER_DEFAULT = "false"; // don't quit
31 
32     private Bundle mArguments;
33 
34     /**
35      * Called reflectively on classes annotated with {@code @RunWith(LongevitySuite.class)}
36      */
LongevitySuite(Class<T> klass, RunnerBuilder builder)37     public LongevitySuite(Class<T> klass, RunnerBuilder builder) throws InitializationError {
38         this(klass, builder, InstrumentationRegistry.getArguments());
39     }
40 
41     /**
42      * Called by tests in order to pass in configurable arguments without affecting the registry.
43      */
44     @VisibleForTesting
LongevitySuite(Class<T> klass, RunnerBuilder builder, Bundle args)45     LongevitySuite(Class<T> klass, RunnerBuilder builder, Bundle args)
46             throws InitializationError {
47         this(klass, constructClassRunners(klass, builder, args), args);
48     }
49 
50     /**
51      * Called by this class once the suite class and runners have been determined.
52      */
LongevitySuite(Class<T> klass, List<Runner> runners, Bundle args)53     private LongevitySuite(Class<T> klass, List<Runner> runners, Bundle args)
54             throws InitializationError {
55         super(klass, runners);
56         mArguments = args;
57     }
58 
59     /**
60      * Constructs the sequence of {@link Runner}s that produce the full longevity test.
61      */
constructClassRunners( Class<?> suite, RunnerBuilder builder, Bundle args)62     private static List<Runner> constructClassRunners(
63                 Class<?> suite, RunnerBuilder builder, Bundle args) throws InitializationError {
64         // Retrieve annotated suite classes.
65         SuiteClasses annotation = suite.getAnnotation(SuiteClasses.class);
66         if (annotation == null) {
67             throw new InitializationError(String.format(
68                     "Longevity suite, '%s', must have a SuiteClasses annotation", suite.getName()));
69         }
70         // Construct and store custom runners for the full suite.
71         BiFunction<Bundle, List<Runner>, List<Runner>> modifier =
72             new Iterate().andThen(new Shuffle());
73         return modifier.apply(args, builder.runners(suite, annotation.value()));
74     }
75 
76     @Override
run(final RunNotifier notifier)77     public void run(final RunNotifier notifier) {
78         // Add action terminators for custom runner logic.
79         notifier.addListener(
80                 new BatteryTerminator(notifier, mArguments, InstrumentationRegistry.getContext()));
81         notifier.addListener(
82                 new TimeoutTerminator(notifier, mArguments));
83         if (Boolean.parseBoolean(
84                 mArguments.getString(QUITTER_OPTION, String.valueOf(QUITTER_DEFAULT)))) {
85             notifier.addListener(new ErrorTerminator(notifier));
86         }
87         // Invoke tests to run through super call.
88         super.run(notifier);
89     }
90 }
91