• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.test;
6 
7 import android.app.Instrumentation;
8 import android.content.Context;
9 import android.os.Bundle;
10 import android.os.SystemClock;
11 
12 import junit.framework.TestCase;
13 import junit.framework.TestResult;
14 
15 import org.chromium.base.Log;
16 import org.chromium.base.test.util.SkipCheck;
17 
18 import java.lang.reflect.Method;
19 import java.util.ArrayList;
20 import java.util.List;
21 
22 /**
23  * A test result that can skip tests.
24  */
25 public class BaseTestResult extends TestResult {
26     private static final String TAG = "base_test";
27 
28     private static final int SLEEP_INTERVAL_MS = 50;
29     private static final int WAIT_DURATION_MS = 5000;
30 
31     private final Instrumentation mInstrumentation;
32     private final List<SkipCheck> mSkipChecks;
33     private final List<PreTestHook> mPreTestHooks;
34 
35     /**
36      * Creates an instance of BaseTestResult.
37      */
BaseTestResult(Instrumentation instrumentation)38     public BaseTestResult(Instrumentation instrumentation) {
39         mSkipChecks = new ArrayList<>();
40         mPreTestHooks = new ArrayList<>();
41         mInstrumentation = instrumentation;
42     }
43 
44     /**
45      * An interface for classes that have some code to run before a test. They run after
46      * {@link SkipCheck}s. Provides access to the test method (and the annotations defined for it)
47      * and the instrumentation context.
48      */
49     public interface PreTestHook {
50         /**
51          * @param targetContext the instrumentation context that will be used during the test.
52          * @param testMethod the test method to be run.
53          */
run(Context targetContext, Method testMethod)54         public void run(Context targetContext, Method testMethod);
55     }
56 
57     /**
58      * Adds a check for whether a test should run.
59      *
60      * @param skipCheck The check to add.
61      */
addSkipCheck(SkipCheck skipCheck)62     public void addSkipCheck(SkipCheck skipCheck) {
63         mSkipChecks.add(skipCheck);
64     }
65 
66     /**
67      * Adds hooks that will be executed before each test that runs.
68      *
69      * @param preTestHook The hook to add.
70      */
addPreTestHook(PreTestHook preTestHook)71     public void addPreTestHook(PreTestHook preTestHook) {
72         mPreTestHooks.add(preTestHook);
73     }
74 
shouldSkip(TestCase test)75     protected boolean shouldSkip(TestCase test) {
76         for (SkipCheck s : mSkipChecks) {
77             if (s.shouldSkip(test)) return true;
78         }
79         return false;
80     }
81 
runPreTestHooks(TestCase test)82     private void runPreTestHooks(TestCase test) {
83         try {
84             Method testMethod = test.getClass().getMethod(test.getName());
85             Context targetContext = getTargetContext();
86 
87             for (PreTestHook hook : mPreTestHooks) {
88                 hook.run(targetContext, testMethod);
89             }
90         } catch (NoSuchMethodException e) {
91             Log.e(TAG, "Unable to run pre test hooks.", e);
92         }
93     }
94 
95     @Override
run(TestCase test)96     protected void run(TestCase test) {
97         runPreTestHooks(test);
98 
99         if (shouldSkip(test)) {
100             startTest(test);
101 
102             Bundle skipResult = new Bundle();
103             skipResult.putString("class", test.getClass().getName());
104             skipResult.putString("test", test.getName());
105             skipResult.putBoolean("test_skipped", true);
106             mInstrumentation.sendStatus(0, skipResult);
107 
108             endTest(test);
109         } else {
110             super.run(test);
111         }
112     }
113 
114     /**
115      * Gets the target context.
116      *
117      * On older versions of Android, getTargetContext() may initially return null, so we have to
118      * wait for it to become available.
119      *
120      * @return The target {@link Context} if available; null otherwise.
121      */
getTargetContext()122     public Context getTargetContext() {
123         Context targetContext = mInstrumentation.getTargetContext();
124         try {
125             long startTime = SystemClock.uptimeMillis();
126             // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
127             while (targetContext == null
128                     && SystemClock.uptimeMillis() - startTime < WAIT_DURATION_MS) {
129                 Thread.sleep(SLEEP_INTERVAL_MS);
130                 targetContext = mInstrumentation.getTargetContext();
131             }
132         } catch (InterruptedException e) {
133             Log.e(TAG, "Interrupted while attempting to initialize the command line.");
134         }
135         return targetContext;
136     }
137 }
138