[Android] Support conditional test disabling based on android.os.Build values.
BUG=565324
TBR=thakis@chromium.org
Review URL: https://codereview.chromium.org/1519523002
Cr-Commit-Position: refs/heads/master@{#366465}
CrOS-Libchrome-Original-Commit: ae13c65b3c776429bcc48968855112607db595a0
diff --git a/base/base.gyp b/base/base.gyp
index 7408d05..dc484f4 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -1588,7 +1588,7 @@
],
'variables': {
'src_paths': [
- '../base/test/android/junit/',
+ '../base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java',
],
},
'includes': [ '../build/host_jar.gypi' ]
@@ -1607,6 +1607,7 @@
'main_class': 'org.chromium.testing.local.JunitTestMain',
'src_paths': [
'../base/android/junit/',
+ '../base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java',
],
},
'includes': [ '../build/host_jar.gypi' ],
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index 58e5b1c..8bf3d0f 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -19,10 +19,11 @@
import org.chromium.base.Log;
import org.chromium.base.SysUtils;
import org.chromium.base.multidex.ChromiumMultiDex;
-import org.chromium.base.test.BaseTestResult.SkipCheck;
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;
@@ -64,24 +65,21 @@
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 implements SkipCheck {
+ public class RestrictionSkipCheck extends SkipCheck {
@Override
public boolean shouldSkip(TestCase testCase) {
- Method method;
- try {
- method = testCase.getClass().getMethod(testCase.getName(), (Class[]) null);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Unable to find %s in %s", testCase.getName(),
- testCase.getClass().getName(), e);
- return true;
- }
+ Method method = getTestMethod(testCase);
+ if (method == null) return true;
+
Restriction restrictions = method.getAnnotation(Restriction.class);
if (restrictions != null) {
for (String restriction : restrictions.value()) {
@@ -120,7 +118,7 @@
/**
* Checks the device's SDK level against any specified minimum requirement.
*/
- public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
+ public static class MinAndroidSdkLevelSkipCheck extends SkipCheck {
/**
* If {@link MinAndroidSdkLevel} is present, checks its value
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
index 7ac4bee..1de03ac 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseTestResult.java
@@ -15,6 +15,7 @@
import org.chromium.base.Log;
import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.SkipCheck;
import org.chromium.base.test.util.parameter.BaseParameter;
import org.chromium.base.test.util.parameter.Parameter;
import org.chromium.base.test.util.parameter.Parameterizable;
@@ -53,20 +54,6 @@
}
/**
- * An interface for classes that check whether a test case should be skipped.
- */
- public interface SkipCheck {
- /**
- *
- * Checks whether the given test case should be skipped.
- *
- * @param testCase The test case to check.
- * @return Whether the test case should be skipped.
- */
- boolean shouldSkip(TestCase testCase);
- }
-
- /**
* An interface for classes that have some code to run before a test. They run after
* {@link SkipCheck}s. Provides access to the test method (and the annotations defined for it)
* and the instrumentation context.
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisableIf.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisableIf.java
new file mode 100644
index 0000000..ee89726
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/DisableIf.java
@@ -0,0 +1,38 @@
+// Copyright 2015 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.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotations to support conditional test disabling.
+ *
+ * These annotations should only be used to disable tests that are temporarily failing
+ * in some configurations. If a test should never run at all in some configurations, use
+ * {@link Restriction}.
+ */
+public class DisableIf {
+
+ /** Conditional disabling based on {@link android.os.Build}.
+ */
+ @Target({ElementType.METHOD, ElementType.TYPE})
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface Build {
+ String message() default "";
+
+ int sdk_is_greater_than() default 0;
+ int sdk_is_less_than() default Integer.MAX_VALUE;
+
+ String supported_abis_includes() default "";
+
+ String hardware_is() default "";
+ }
+
+ /* Objects of this type should not be created. */
+ private DisableIf() {}
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java
new file mode 100644
index 0000000..7da6de8
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java
@@ -0,0 +1,68 @@
+// Copyright 2015 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.util;
+
+import android.os.Build;
+
+import junit.framework.TestCase;
+
+import org.chromium.base.Log;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+/**
+ * Checks for conditional disables.
+ *
+ * Currently, this only includes checks against a few {@link android.os.Build} values.
+ */
+public class DisableIfSkipCheck extends SkipCheck {
+
+ private static final String TAG = "cr_base_test";
+
+ @Override
+ public boolean shouldSkip(TestCase testCase) {
+ Method method = getTestMethod(testCase);
+ if (method == null) return true;
+
+ if (method.isAnnotationPresent(DisableIf.Build.class)) {
+ DisableIf.Build v = method.getAnnotation(DisableIf.Build.class);
+
+ if (abi(v) && hardware(v) && sdk(v)) {
+ if (!v.message().isEmpty()) {
+ Log.i(TAG, "%s is disabled: %s", testCase.toString(), v.message());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean abi(DisableIf.Build v) {
+ if (v.supported_abis_includes().isEmpty()) return true;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ return Arrays.asList(Build.SUPPORTED_ABIS).contains(
+ v.supported_abis_includes());
+ } else {
+ return Build.CPU_ABI.equals(v.supported_abis_includes())
+ || Build.CPU_ABI2.equals(v.supported_abis_includes());
+ }
+ }
+
+ private boolean hardware(DisableIf.Build v) {
+ return v.hardware_is().isEmpty() || Build.HARDWARE.equals(v.hardware_is());
+ }
+
+ private boolean sdk(DisableIf.Build v) {
+ return Build.VERSION.SDK_INT > v.sdk_is_greater_than()
+ && Build.VERSION.SDK_INT < v.sdk_is_less_than();
+ }
+
+}
+
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/SkipCheck.java b/base/test/android/javatests/src/org/chromium/base/test/util/SkipCheck.java
new file mode 100644
index 0000000..cb21dfd
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/SkipCheck.java
@@ -0,0 +1,39 @@
+// Copyright 2015 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.util;
+
+import junit.framework.TestCase;
+
+import org.chromium.base.Log;
+
+import java.lang.reflect.Method;
+
+/**
+ * Check whether a test case should be skipped.
+ */
+public abstract class SkipCheck {
+
+ private static final String TAG = "base_test";
+
+ /**
+ *
+ * Checks whether the given test case should be skipped.
+ *
+ * @param testCase The test case to check.
+ * @return Whether the test case should be skipped.
+ */
+ public abstract boolean shouldSkip(TestCase testCase);
+
+ protected static Method getTestMethod(TestCase testCase) {
+ try {
+ return testCase.getClass().getMethod(testCase.getName(), (Class[]) null);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Unable to find %s in %s", testCase.getName(),
+ testCase.getClass().getName(), e);
+ return null;
+ }
+ }
+}
+
diff --git a/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java b/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java
new file mode 100644
index 0000000..c4920a8
--- /dev/null
+++ b/base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java
@@ -0,0 +1,160 @@
+// Copyright 2015 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.util;
+
+import android.os.Build;
+
+import junit.framework.TestCase;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+
+/** Unit tests for the DisableIf annotation and its SkipCheck implementation. */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, reportSdk = 19)
+public class DisableIfTest {
+
+ @Test
+ public void testSdkIsLessThanAndIsLessThan() {
+ TestCase sdkIsLessThan = new TestCase("sdkIsLessThan") {
+ @DisableIf.Build(sdk_is_less_than = 21)
+ public void sdkIsLessThan() {}
+ };
+ Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sdkIsLessThan));
+ }
+
+ @Test
+ public void testSdkIsLessThanButIsEqual() {
+ TestCase sdkIsEqual = new TestCase("sdkIsEqual") {
+ @DisableIf.Build(sdk_is_less_than = 19)
+ public void sdkIsEqual() {}
+ };
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsEqual));
+ }
+
+ @Test
+ public void testSdkIsLessThanButIsGreaterThan() {
+ TestCase sdkIsGreaterThan = new TestCase("sdkIsGreaterThan") {
+ @DisableIf.Build(sdk_is_less_than = 16)
+ public void sdkIsGreaterThan() {}
+ };
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsGreaterThan));
+ }
+
+ @Test
+ public void testSdkIsGreaterThanButIsLessThan() {
+ TestCase sdkIsLessThan = new TestCase("sdkIsLessThan") {
+ @DisableIf.Build(sdk_is_greater_than = 21)
+ public void sdkIsLessThan() {}
+ };
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsLessThan));
+ }
+
+ @Test
+ public void testSdkIsGreaterThanButIsEqual() {
+ TestCase sdkIsEqual = new TestCase("sdkIsEqual") {
+ @DisableIf.Build(sdk_is_greater_than = 19)
+ public void sdkIsEqual() {}
+ };
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(sdkIsEqual));
+ }
+
+ @Test
+ public void testSdkIsGreaterThanAndIsGreaterThan() {
+ TestCase sdkIsGreaterThan = new TestCase("sdkIsGreaterThan") {
+ @DisableIf.Build(sdk_is_greater_than = 16)
+ public void sdkIsGreaterThan() {}
+ };
+ Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(sdkIsGreaterThan));
+ }
+
+ @Test
+ public void testSupportedAbiIncludesAndCpuAbiMatches() {
+ TestCase supportedAbisCpuAbiMatch = new TestCase("supportedAbisCpuAbiMatch") {
+ @DisableIf.Build(supported_abis_includes = "foo")
+ public void supportedAbisCpuAbiMatch() {}
+ };
+ String originalAbi = Build.CPU_ABI;
+ String originalAbi2 = Build.CPU_ABI2;
+ try {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", "foo");
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", "bar");
+ Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(supportedAbisCpuAbiMatch));
+ } finally {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", originalAbi);
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", originalAbi2);
+ }
+ }
+
+ @Test
+ public void testSupportedAbiIncludesAndCpuAbi2Matches() {
+ TestCase supportedAbisCpuAbi2Match = new TestCase("supportedAbisCpuAbi2Match") {
+ @DisableIf.Build(supported_abis_includes = "bar")
+ public void supportedAbisCpuAbi2Match() {}
+ };
+ String originalAbi = Build.CPU_ABI;
+ String originalAbi2 = Build.CPU_ABI2;
+ try {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", "foo");
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", "bar");
+ Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(supportedAbisCpuAbi2Match));
+ } finally {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", originalAbi);
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", originalAbi2);
+ }
+ }
+
+ @Test
+ public void testSupportedAbiIncludesButNoMatch() {
+ TestCase supportedAbisNoMatch = new TestCase("supportedAbisNoMatch") {
+ @DisableIf.Build(supported_abis_includes = "baz")
+ public void supportedAbisNoMatch() {}
+ };
+ String originalAbi = Build.CPU_ABI;
+ String originalAbi2 = Build.CPU_ABI2;
+ try {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", "foo");
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", "bar");
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(supportedAbisNoMatch));
+ } finally {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI", originalAbi);
+ Robolectric.Reflection.setFinalStaticField(Build.class, "CPU_ABI2", originalAbi2);
+ }
+ }
+
+ @Test
+ public void testHardwareIsMatches() {
+ TestCase hardwareIsMatches = new TestCase("hardwareIsMatches") {
+ @DisableIf.Build(hardware_is = "hammerhead")
+ public void hardwareIsMatches() {}
+ };
+ String originalHardware = Build.HARDWARE;
+ try {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "HARDWARE", "hammerhead");
+ Assert.assertTrue(new DisableIfSkipCheck().shouldSkip(hardwareIsMatches));
+ } finally {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "HARDWARE", originalHardware);
+ }
+ }
+
+ @Test
+ public void testHardwareIsDoesntMatch() {
+ TestCase hardwareIsDoesntMatch = new TestCase("hardwareIsDoesntMatch") {
+ @DisableIf.Build(hardware_is = "hammerhead")
+ public void hardwareIsDoesntMatch() {}
+ };
+ String originalHardware = Build.HARDWARE;
+ try {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "HARDWARE", "mako");
+ Assert.assertFalse(new DisableIfSkipCheck().shouldSkip(hardwareIsDoesntMatch));
+ } finally {
+ Robolectric.Reflection.setFinalStaticField(Build.class, "HARDWARE", originalHardware);
+ }
+ }
+}