summaryrefslogtreecommitdiffstats
path: root/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
blob: 8bf3d0fb454b9463ec303e091dc8ebceff432365 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.base.test;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.test.AndroidTestRunner;
import android.test.InstrumentationTestRunner;
import android.text.TextUtils;

import junit.framework.TestCase;
import junit.framework.TestResult;

import org.chromium.base.Log;
import org.chromium.base.SysUtils;
import org.chromium.base.multidex.ChromiumMultiDex;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisableIfSkipCheck;
import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.base.test.util.Restriction;
import org.chromium.base.test.util.SkipCheck;
import org.chromium.test.reporter.TestStatusListener;

import java.lang.reflect.Method;

// TODO(jbudorick): Add support for on-device handling of timeouts.
/**
 *  An Instrumentation test runner that checks SDK level for tests with specific requirements.
 */
public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
    private static final String TAG = "base_test";

    @Override
    public void onCreate(Bundle arguments) {
        ChromiumMultiDex.install(getTargetContext());
        super.onCreate(arguments);
    }

    @Override
    protected AndroidTestRunner getAndroidTestRunner() {
        AndroidTestRunner runner = new AndroidTestRunner() {
            @Override
            protected TestResult createTestResult() {
                BaseTestResult r = new BaseTestResult(BaseInstrumentationTestRunner.this);
                addTestHooks(r);
                return r;
            }
        };
        runner.addTestListener(new TestStatusListener(getContext()));
        return runner;
    }

    /**
     * Override this method to register hooks and checks to be run for each test. Make sure to call
     * the base implementation if you do so.
     *
     * @see BaseTestResult#addSkipCheck(BaseTestResult.SkipCheck)
     * @see BaseTestResult#addPreTestHook(BaseTestResult.PreTestHook)
     */
    protected void addTestHooks(BaseTestResult result) {
        result.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
        result.addSkipCheck(new RestrictionSkipCheck());
        result.addSkipCheck(new DisableIfSkipCheck());

        result.addPreTestHook(CommandLineFlags.getRegistrationHook());
    }


    /**
     * Checks if any restrictions exist and skip the test if it meets those restrictions.
     */
    public class RestrictionSkipCheck extends SkipCheck {
        @Override
        public boolean shouldSkip(TestCase testCase) {
            Method method = getTestMethod(testCase);
            if (method == null) return true;

            Restriction restrictions = method.getAnnotation(Restriction.class);
            if (restrictions != null) {
                for (String restriction : restrictions.value()) {
                    if (restrictionApplies(restriction)) {
                        return true;
                    }
                }
            }
            return false;
        }

        protected boolean restrictionApplies(String restriction) {
            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_LOW_END_DEVICE)
                    && !SysUtils.isLowEndDevice()) {
                return true;
            }
            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE)
                    && SysUtils.isLowEndDevice()) {
                return true;
            }
            if (TextUtils.equals(restriction, Restriction.RESTRICTION_TYPE_INTERNET)
                    && !isNetworkAvailable()) {
                return true;
            }
            return false;
        }

        private boolean isNetworkAvailable() {
            final ConnectivityManager connectivityManager = (ConnectivityManager)
                    getTargetContext().getSystemService(Context.CONNECTIVITY_SERVICE);
            final NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            return activeNetworkInfo != null && activeNetworkInfo.isConnected();
        }
    }

    /**
     * Checks the device's SDK level against any specified minimum requirement.
     */
    public static class MinAndroidSdkLevelSkipCheck extends SkipCheck {

        /**
         * If {@link MinAndroidSdkLevel} is present, checks its value
         * against the device's SDK level.
         *
         * @param testCase The test to check.
         * @return true if the device's SDK level is below the specified minimum.
         */
        @Override
        public boolean shouldSkip(TestCase testCase) {
            Class<?> testClass = testCase.getClass();
            if (testClass.isAnnotationPresent(MinAndroidSdkLevel.class)) {
                MinAndroidSdkLevel v = testClass.getAnnotation(MinAndroidSdkLevel.class);
                if (Build.VERSION.SDK_INT < v.value()) {
                    Log.i(TAG, "Test " + testClass.getName() + "#" + testCase.getName()
                            + " is not enabled at SDK level " + Build.VERSION.SDK_INT
                            + ".");
                    return true;
                }
            }
            return false;
        }
    }
}