diff options
author | dgn <dgn@chromium.org> | 2015-11-10 07:33:50 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-10 15:34:41 +0000 |
commit | 738fa38d347a0f3f71a41c23cb4f03618e071d7c (patch) | |
tree | 7077acf341277cc5ea55f56e671b7f1cf102e4f0 | |
parent | af229b2ae84edd77a6c5c40adf5e34c88805d630 (diff) | |
download | chromium_src-738fa38d347a0f3f71a41c23cb4f03618e071d7c.zip chromium_src-738fa38d347a0f3f71a41c23cb4f03618e071d7c.tar.gz chromium_src-738fa38d347a0f3f71a41c23cb4f03618e071d7c.tar.bz2 |
Update webview and chrome instrumentation test to use PreTestHooks for policies
- Add utilities to set policies for tests using anotation and pre
test hooks
- Add AwInstrumentationTestRunner and update
ChromeInstrumentationTestRunner to register said hooks
- Add classes to simplify building policy bundles
BUG=542859
Review URL: https://codereview.chromium.org/1387633002
Cr-Commit-Position: refs/heads/master@{#358829}
16 files changed, 501 insertions, 81 deletions
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi index 14c90ca..a5af244 100644 --- a/android_webview/android_webview_tests.gypi +++ b/android_webview/android_webview_tests.gypi @@ -11,6 +11,8 @@ 'android_webview_java', 'android_webview_pak', 'libdrawgl', + '../base/base.gyp:base_java_test_support', + '../components/components.gyp:policy_java_test_support' ], 'variables': { 'apk_name': 'AndroidWebView', @@ -96,6 +98,7 @@ 'type': 'none', 'dependencies': [ '../base/base.gyp:base_java_test_support', + '../components/components.gyp:policy_java_test_support', '../content/content_shell_and_tests.gyp:content_java_test_support', '../net/net.gyp:net_java_test_support', '../testing/android/on_device_instrumentation.gyp:broker_java', diff --git a/android_webview/javatests/AndroidManifest.xml b/android_webview/javatests/AndroidManifest.xml index fb3db24..ed0ae66 100644 --- a/android_webview/javatests/AndroidManifest.xml +++ b/android_webview/javatests/AndroidManifest.xml @@ -5,7 +5,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.chromium.android_webview.test"> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" /> - <instrumentation android:name="org.chromium.base.test.BaseInstrumentationTestRunner" + <instrumentation android:name="org.chromium.android_webview.test.AwInstrumentationTestRunner" android:targetPackage="org.chromium.android_webview.shell" android:label="Tests for org.chromium.android_webview"/> <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> diff --git a/android_webview/javatests/DEPS b/android_webview/javatests/DEPS index e2a33b1..24ccfae 100644 --- a/android_webview/javatests/DEPS +++ b/android_webview/javatests/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+components/external_video_surface/android/java", "+components/policy/android/java", + "+components/policy/android/javatests", "+content/public/android/java", "+content/public/test/android/javatests", ] diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PolicyUrlFilteringTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PolicyUrlFilteringTest.java index 7c2629e..32bdae7 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PolicyUrlFilteringTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PolicyUrlFilteringTest.java @@ -4,10 +4,8 @@ package org.chromium.android_webview.test; -import android.os.Bundle; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; import android.util.Pair; import org.chromium.android_webview.AwContents; @@ -17,9 +15,13 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.test.util.TestCallbackHelperContainer; import org.chromium.net.test.util.TestWebServer; +import org.chromium.policy.AbstractAppRestrictionsProvider; import org.chromium.policy.CombinedPolicyProvider; +import org.chromium.policy.test.PolicyData; +import org.chromium.policy.test.annotations.Policies; import java.util.ArrayList; +import java.util.Arrays; /** Tests for the policy based URL filtering. */ public class PolicyUrlFilteringTest extends AwTestBase { @@ -28,7 +30,8 @@ public class PolicyUrlFilteringTest extends AwTestBase { private TestWebServer mWebServer; private String mFooTestUrl; private String mBarTestUrl; - private AwPolicyProvider mTestProvider; + private static final String sFooTestFilePath = "/foo.html"; + private static final String sFooWhitelistFilter = "localhost" + sFooTestFilePath; private static final String sBlacklistPolicyName = "com.android.browser:URLBlacklist"; private static final String sWhitelistPolicyName = "com.android.browser:URLWhitelist"; @@ -36,21 +39,14 @@ public class PolicyUrlFilteringTest extends AwTestBase { @Override public void setUp() throws Exception { super.setUp(); - setTestAwContentsClient(new TestAwContentsClient()); + mContentsClient = new TestAwContentsClient(); + mAwContents = createAwTestContainerViewOnMainSync(mContentsClient).getAwContents(); mWebServer = TestWebServer.start(); - mFooTestUrl = mWebServer.setResponse("/foo.html", "<html><body>foo</body></html>", + mFooTestUrl = mWebServer.setResponse(sFooTestFilePath, "<html><body>foo</body></html>", new ArrayList<Pair<String, String>>()); mBarTestUrl = mWebServer.setResponse("/bar.html", "<html><body>bar</body></html>", new ArrayList<Pair<String, String>>()); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mTestProvider = new AwPolicyProvider(getActivity().getApplicationContext()); - CombinedPolicyProvider.get().registerProvider(mTestProvider); - } - }); - getInstrumentation().waitForIdleSync(); } @@ -60,97 +56,83 @@ public class PolicyUrlFilteringTest extends AwTestBase { super.tearDown(); } - private void setTestAwContentsClient(TestAwContentsClient contentsClient) throws Exception { - mContentsClient = contentsClient; - final AwTestContainerView testContainerView = - createAwTestContainerViewOnMainSync(mContentsClient); - mAwContents = testContainerView.getAwContents(); - } - // Tests transforming the bundle to native policies, reloading the policies and blocking // the navigation. @MediumTest @Feature({"AndroidWebView", "Policy"}) public void testBlacklistedUrl() throws Throwable { - TestCallbackHelperContainer.OnReceivedErrorHelper onReceivedErrorHelper = - mContentsClient.getOnReceivedErrorHelper(); - TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mContentsClient.getOnPageFinishedHelper(); + final AwPolicyProvider testProvider = + new AwPolicyProvider(getActivity().getApplicationContext()); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + CombinedPolicyProvider.get().registerProvider(testProvider); + } + }); - loadUrlSync(mAwContents, onPageFinishedHelper, mFooTestUrl); - assertEquals(mFooTestUrl, onPageFinishedHelper.getUrl()); - assertEquals(0, onReceivedErrorHelper.getCallCount()); + navigateAndCheckOutcome(mFooTestUrl, 0); - setFilteringPolicy(new String[] {"localhost"}, new String[] {}); + setFilteringPolicy(testProvider, new String[] {"localhost"}, new String[] {}); - loadUrlSync(mAwContents, onPageFinishedHelper, mFooTestUrl); - assertEquals(mFooTestUrl, onPageFinishedHelper.getUrl()); - assertEquals(1, onReceivedErrorHelper.getCallCount()); - assertEquals(ErrorCodeConversionHelper.ERROR_CONNECT, onReceivedErrorHelper.getErrorCode()); + navigateAndCheckOutcome(mFooTestUrl, 1); + assertEquals(ErrorCodeConversionHelper.ERROR_CONNECT, + mContentsClient.getOnReceivedErrorHelper().getErrorCode()); } - // Tests transforming the bundle to native policies, reloading the policies and getting a - // successful navigation with a whitelist. + // Tests getting a successful navigation with a whitelist. @MediumTest @Feature({"AndroidWebView", "Policy"}) + @Policies.Add({ + @Policies.Item(key = sBlacklistPolicyName, stringArray = {"*"}), + @Policies.Item(key = sWhitelistPolicyName, stringArray = {sFooWhitelistFilter})}) public void testWhitelistedUrl() throws Throwable { - TestCallbackHelperContainer.OnReceivedErrorHelper onReceivedErrorHelper = - mContentsClient.getOnReceivedErrorHelper(); - TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = - mContentsClient.getOnPageFinishedHelper(); - setFilteringPolicy(new String[] {"*"}, new String[] {mFooTestUrl}); - - loadUrlSync(mAwContents, onPageFinishedHelper, mFooTestUrl); - assertEquals(mFooTestUrl, onPageFinishedHelper.getUrl()); - assertEquals(0, onReceivedErrorHelper.getCallCount()); + navigateAndCheckOutcome(mFooTestUrl, 0); // Make sure it goes through the blacklist - loadUrlSync(mAwContents, onPageFinishedHelper, mBarTestUrl); - assertEquals(mBarTestUrl, onPageFinishedHelper.getUrl()); - assertEquals(1, onReceivedErrorHelper.getCallCount()); - assertEquals(ErrorCodeConversionHelper.ERROR_CONNECT, onReceivedErrorHelper.getErrorCode()); + navigateAndCheckOutcome(mBarTestUrl, 1); + assertEquals(ErrorCodeConversionHelper.ERROR_CONNECT, + mContentsClient.getOnReceivedErrorHelper().getErrorCode()); } // Tests that bad policy values are properly handled @SmallTest @Feature({"AndroidWebView", "Policy"}) + @Policies.Add({ + @Policies.Item(key = sBlacklistPolicyName, string = "shouldBeAJsonArrayNotAString")}) public void testBadPolicyValue() throws Exception { - final Bundle newPolicies = new Bundle(); - newPolicies.putString(sBlacklistPolicyName, "shouldBeAJsonArrayNotAString"); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mTestProvider.notifySettingsAvailable(newPolicies); - } - }); - getInstrumentation().waitForIdleSync(); + navigateAndCheckOutcome(mFooTestUrl, 0); + // At the moment this test is written, a failure is a crash, a success is no crash. + } + /** + * Synchronously loads the provided URL and checks that the number or reported errors for the + * current context is the expected one. + */ + private void navigateAndCheckOutcome(String url, int expectedErrorCount) throws Exception { + TestCallbackHelperContainer.OnReceivedErrorHelper onReceivedErrorHelper = + mContentsClient.getOnReceivedErrorHelper(); TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper(); - loadUrlSync(mAwContents, onPageFinishedHelper, mFooTestUrl); - // At the moment this test is written, a failure is a crash, a success is no crash. + loadUrlSync(mAwContents, onPageFinishedHelper, url); + assertEquals(url, onPageFinishedHelper.getUrl()); + assertEquals(expectedErrorCount, onReceivedErrorHelper.getCallCount()); } - private void setFilteringPolicy(final String[] blacklistUrls, final String[] whitelistUrls) { - final Bundle newPolicies = new Bundle(); - - if (blacklistUrls != null && blacklistUrls.length > 0) { - String blacklistString = - String.format("[\"%s\"]", TextUtils.join("\",\"", blacklistUrls)); - newPolicies.putString(sBlacklistPolicyName, blacklistString); - } + private void setFilteringPolicy(final AwPolicyProvider testProvider, + final String[] blacklistUrls, final String[] whitelistUrls) { + final PolicyData[] policies = { + new PolicyData.StrArray(sBlacklistPolicyName, blacklistUrls), + new PolicyData.StrArray(sWhitelistPolicyName, whitelistUrls) + }; - if (whitelistUrls != null && whitelistUrls.length > 0) { - String whitelistString = - String.format("[\"%s\"]", TextUtils.join("\",\"", whitelistUrls)); - newPolicies.putString(sWhitelistPolicyName, whitelistString); - } + AbstractAppRestrictionsProvider.setTestRestrictions( + PolicyData.asBundle(Arrays.asList(policies))); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - mTestProvider.notifySettingsAvailable(newPolicies); + testProvider.refresh(); } }); diff --git a/android_webview/test/shell/DEPS b/android_webview/test/shell/DEPS index 0d019e1..2a76d5b 100644 --- a/android_webview/test/shell/DEPS +++ b/android_webview/test/shell/DEPS @@ -1,3 +1,4 @@ include_rules = [ + "+components/policy/android/javatests", "+content/public/android/java", ] diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwInstrumentationTestRunner.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwInstrumentationTestRunner.java new file mode 100644 index 0000000..84f9ceb --- /dev/null +++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwInstrumentationTestRunner.java @@ -0,0 +1,22 @@ +// 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.android_webview.test; + +import org.chromium.base.test.BaseInstrumentationTestRunner; +import org.chromium.base.test.BaseTestResult; +import org.chromium.policy.test.annotations.Policies; + +/** + * Instrumentation test runner that allows integrating features defined above base layer + * for webview testing. + */ +public class AwInstrumentationTestRunner extends BaseInstrumentationTestRunner { + @Override + protected void addTestHooks(BaseTestResult result) { + super.addTestHooks(result); + + result.addPreTestHook(Policies.getRegistrationHook()); + } +} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index fc6b75b..bbf0c97 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -3152,6 +3152,7 @@ 'chrome_java', '../base/base.gyp:base_java', '../base/base.gyp:base_java_test_support', + '../components/components.gyp:policy_java_test_support', '../content/content_shell_and_tests.gyp:content_java_test_support', '../net/net.gyp:net_java', '../net/net.gyp:net_java_test_support', diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn index 6b59c31..1f65910 100644 --- a/chrome/test/android/BUILD.gn +++ b/chrome/test/android/BUILD.gn @@ -16,6 +16,7 @@ android_library("chrome_java_test_support") { "//components/bookmarks/common/android:bookmarks_java", "//components/invalidation/impl:java", "//components/policy/android:policy_java", + "//components/policy/android:policy_java_test_support", "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//content/public/android:content_java", "//content/public/test/android:content_java_test_support", diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java index 16cfa52..2abc171 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java @@ -19,6 +19,7 @@ import org.chromium.base.test.util.Restriction; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.test.util.DisableInTabbedMode; import org.chromium.net.test.BaseHttpTestServer; +import org.chromium.policy.test.annotations.Policies; import org.chromium.ui.base.DeviceFormFactor; import java.io.File; @@ -214,6 +215,8 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn super.addTestHooks(result); result.addSkipCheck(new DisableInTabbedModeSkipCheck()); result.addSkipCheck(new ChromeRestrictionSkipCheck()); + + result.addPreTestHook(Policies.getRegistrationHook()); } private class ChromeRestrictionSkipCheck extends RestrictionSkipCheck { diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 198e0765..f9975f0 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -1567,17 +1567,12 @@ 'type': 'none', 'dependencies': [ 'components.gyp:invalidation_java', + 'components.gyp:policy_java', + 'components.gyp:policy_java_test_support', '../base/base.gyp:base_java', '../base/base.gyp:base_java_test_support', '../testing/android/junit/junit_test.gyp:junit_test_support', ], - 'conditions': [ - ['configuration_policy == 1', { - 'dependencies': [ - 'components.gyp:policy_java', - ], - }], - ], 'variables': { 'main_class': 'org.chromium.testing.local.JunitTestMain', 'src_paths': [ diff --git a/components/policy.gypi b/components/policy.gypi index 7788538..6380877 100644 --- a/components/policy.gypi +++ b/components/policy.gypi @@ -427,6 +427,20 @@ }, 'includes': [ '../build/java.gypi' ], }, + { + # GN: //components/policy/android:policy_java_test_support + 'target_name': 'policy_java_test_support', + 'type': 'none', + 'dependencies': [ + '../base/base.gyp:base_java', + '../base/base.gyp:base_java_test_support', + 'policy_java' + ], + 'variables': { + 'java_in_dir': 'policy/android/javatests', + }, + 'includes': [ '../build/java.gypi' ], + }, ], }], ['OS=="win" and target_arch=="ia32" and configuration_policy==1', { diff --git a/components/policy/android/BUILD.gn b/components/policy/android/BUILD.gn index 53bc165..ab1003b 100644 --- a/components/policy/android/BUILD.gn +++ b/components/policy/android/BUILD.gn @@ -22,6 +22,20 @@ android_library("policy_java") { ] } +# GYP: //components/components.gyp:policy_test_support_java +android_library("policy_java_test_support") { + testonly = true + deps = [ + "//base:base_java", + "//base:base_java_test_support", + ":policy_java", + ] + java_files = [ + "javatests/src/org/chromium/policy/test/annotations/Policies.java", + "javatests/src/org/chromium/policy/test/PolicyData.java", + ] +} + # GYP: //components/components.gyp:policy_jni_headers generate_jni("jni_headers") { visibility = [ "//components/policy/*" ] @@ -29,13 +43,17 @@ generate_jni("jni_headers") { jni_package = "policy" } +# GYP: //components/components_test.gyp:components_junit_tests junit_binary("components_policy_junit_tests") { java_files = [ "junit/src/org/chromium/policy/AbstractAppRestrictionsProviderTest.java", "junit/src/org/chromium/policy/CombinedPolicyProviderTest.java", + "junit/src/org/chromium/policy/test/annotations/PoliciesTest.java", ] deps = [ - "//base:base_java", + ":policy_java_test_support", ":policy_java", + "//base:base_java", + "//third_party/junit:hamcrest", ] } diff --git a/components/policy/android/java/src/org/chromium/policy/AbstractAppRestrictionsProvider.java b/components/policy/android/java/src/org/chromium/policy/AbstractAppRestrictionsProvider.java index 60b40bd..82b1939 100644 --- a/components/policy/android/java/src/org/chromium/policy/AbstractAppRestrictionsProvider.java +++ b/components/policy/android/java/src/org/chromium/policy/AbstractAppRestrictionsProvider.java @@ -15,6 +15,7 @@ import android.os.Parcel; import android.preference.PreferenceManager; import android.util.Base64; +import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; @@ -30,6 +31,11 @@ import java.util.concurrent.Executor; public abstract class AbstractAppRestrictionsProvider extends PolicyProvider { private static final String PREFERENCE_KEY = "App Restrictions"; + private static final String TAG = "policy"; + + /** {@link Bundle} holding the restrictions to be used during tests. */ + private static Bundle sTestRestrictions = null; + private final Context mContext; private final SharedPreferences mSharedPreferences; private final BroadcastReceiver mAppRestrictionsChangedReceiver = new BroadcastReceiver() { @@ -79,6 +85,11 @@ public abstract class AbstractAppRestrictionsProvider extends PolicyProvider { */ @Override public void refresh() { + if (sTestRestrictions != null) { + notifySettingsAvailable(sTestRestrictions); + return; + } + final Bundle cachedResult = getCachedPolicies(); if (cachedResult != null) { notifySettingsAvailable(cachedResult); @@ -169,4 +180,18 @@ public abstract class AbstractAppRestrictionsProvider extends PolicyProvider { void setTaskExecutor(Executor testExecutor) { mExecutor = testExecutor; } + + /** + * Restrictions to be used during tests. Subsequent attempts to retrieve the restrictions will + * return the provided bundle instead. + * + * Chrome and WebView tests are set up to use annotations for policy testing and reset the + * restrictions to an empty bundle if nothing is specified. To stop using a test bundle, + * provide {@code null} as value instead. + */ + @VisibleForTesting + public static void setTestRestrictions(Bundle policies) { + Log.d(TAG, "Test Restrictions: %s", policies.keySet().toArray()); + sTestRestrictions = policies; + } } diff --git a/components/policy/android/javatests/src/org/chromium/policy/test/PolicyData.java b/components/policy/android/javatests/src/org/chromium/policy/test/PolicyData.java new file mode 100644 index 0000000..6b230d8 --- /dev/null +++ b/components/policy/android/javatests/src/org/chromium/policy/test/PolicyData.java @@ -0,0 +1,119 @@ +// 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.policy.test; + +import android.os.Bundle; + +import junit.framework.Assert; + +import org.chromium.base.Log; +import org.json.JSONArray; + +/** + * Helper class to transform Java types to {@link Bundle}s usable by the Policy system. + * + * Use the subclasses to define the data and then transform it using {@link #asBundle(Iterable)} + */ +public abstract class PolicyData { + private static final String TAG = "policy_test"; + private final String mKey; + + public PolicyData(String key) { + mKey = key; + } + + public String getKey() { + return mKey; + } + + public abstract void putInBundle(Bundle bundle); + + public static Bundle asBundle(Iterable<PolicyData> policies) { + Bundle bundle = new Bundle(); + for (PolicyData data : policies) { + Log.d(TAG, "Adding to policy bundle: %s", data); + data.putInBundle(bundle); + } + return bundle; + } + + /** {@link PolicyData} for the {@link String} type. */ + public static class Str extends PolicyData { + private final String mValue; + + public Str(String key, String value) { + super(key); + mValue = value; + } + + public String getValue() { + return mValue; + } + + @Override + public void putInBundle(Bundle bundle) { + bundle.putString(getKey(), mValue); + } + + @Override + public String toString() { + return String.format("PolicyData.Str{%s=%s}", getKey(), mValue); + } + } + + /** {@link PolicyData} with no value, for error states. Doesn't put anything in a bundle.*/ + public static class Undefined extends PolicyData { + public Undefined(String key) { + super(key); + } + + @Override + public void putInBundle(Bundle bundle) { + Assert.fail(String.format( + "Attempted to push the '%s' policy without value to a bundle.", getKey())); + } + + @Override + public String toString() { + return String.format("PolicyData.Undefined{%s}", getKey()); + } + } + + /** + * {@link PolicyData} for the {@link String} array type. + * Outputs a string encoded as a JSON array. + */ + public static class StrArray extends PolicyData { + private final String[] mValue; + + public StrArray(String key, String[] value) { + super(key); + mValue = value.clone(); + } + + public String[] getValue() { + return mValue.clone(); + } + + private String valueToString() { + // JSONArray(Object[]) requires API 19 + JSONArray array = new JSONArray(); + for (String s : mValue) { + array.put(s); + } + return array.toString(); + } + + @Override + public void putInBundle(Bundle bundle) { + bundle.putString(getKey(), valueToString()); + } + + @Override + public String toString() { + return String.format("PolicyData.StrArray{%s=%s}", getKey(), valueToString()); + } + } +}
\ No newline at end of file diff --git a/components/policy/android/javatests/src/org/chromium/policy/test/annotations/Policies.java b/components/policy/android/javatests/src/org/chromium/policy/test/annotations/Policies.java new file mode 100644 index 0000000..11b7be2 --- /dev/null +++ b/components/policy/android/javatests/src/org/chromium/policy/test/annotations/Policies.java @@ -0,0 +1,141 @@ +// 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.policy.test.annotations; + +import android.content.Context; +import android.os.Bundle; + +import junit.framework.Assert; + +import org.chromium.base.VisibleForTesting; +import org.chromium.base.test.BaseTestResult.PreTestHook; +import org.chromium.policy.AbstractAppRestrictionsProvider; +import org.chromium.policy.test.PolicyData; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Annotations and utilities for testing code dependent on policies. + * + * Usage example: + * <pre> + * @Policies.Add({ + * @Policies.Item(key="Foo", string="Bar"), + * @Policies.Item(key="Baz", stringArray={"Baz"}) + * }) + * public class MyTestClass extends BaseActivityInstrumentationTestCase<ContentActivity> { + * + * public void MyTest1() { + * // Will run the Foo and Bar policies set + * } + * + * @Policies.Remove(@Policies.Item(key="Baz")) + * public void MyTest2() { + * // Will run with only the Foo policy set + * } + * } + * </pre> + */ +public final class Policies { + /** Items declared here will be added to the list of used policies. */ + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.TYPE}) + public @interface Add { + Item[] value(); + } + + /** Items declared here will be removed from the list of used policies. */ + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.TYPE}) + public @interface Remove { + Item[] value(); + } + + /** + * Individual policy item. Identified by a {@link #key}, and optional data values. + * At most one value argument (e.g. {@link #string()}, {@link #stringArray()}) can be used. A + * test failure will be caused otherwise. + */ + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.METHOD, ElementType.TYPE}) + public @interface Item { + String key(); + + String string() default ""; + + String[] stringArray() default {}; + } + + /** Parses the annotations to extract usable information as {@link PolicyData} objects. */ + private static Map<String, PolicyData> fromItems(Item[] items) { + Map<String, PolicyData> result = new HashMap<>(); + for (Item item : items) { + PolicyData data = null; + + if (!item.string().isEmpty()) { + Assert.assertNull("There can be at most one type of value for the policy", data); + data = new PolicyData.Str(item.key(), item.string()); + } + + if (item.stringArray().length != 0) { + Assert.assertNull("There can be at most one type of value for the policy", data); + data = new PolicyData.StrArray(item.key(), item.stringArray()); + } + + if (data == null) data = new PolicyData.Undefined(item.key()); + result.put(data.getKey(), data); + } + return result; + } + + /** @see PreTestHook */ + public static PreTestHook getRegistrationHook() { + return new RegistrationHook(); + } + + @VisibleForTesting + static Map<String, PolicyData> getPolicies(AnnotatedElement element) { + AnnotatedElement parent = (element instanceof Method) + ? ((Method) element).getDeclaringClass() + : ((Class<?>) element).getSuperclass(); + Map<String, PolicyData> flags = (parent == null) + ? new HashMap<String, PolicyData>() + : getPolicies(parent); + + if (element.isAnnotationPresent(Policies.Add.class)) { + flags.putAll(fromItems(element.getAnnotation(Policies.Add.class).value())); + } + + if (element.isAnnotationPresent(Policies.Remove.class)) { + flags.keySet().removeAll( + fromItems(element.getAnnotation(Policies.Remove.class).value()).keySet()); + } + + return flags; + } + + /** + * Registration hook for the {@link Policies} annotation family. Before a test, will parse + * the declared policies and use them as cached policies. + */ + public static class RegistrationHook implements PreTestHook { + @Override + public void run(Context targetContext, Method testMethod) { + final Bundle policyBundle = PolicyData.asBundle(getPolicies(testMethod).values()); + AbstractAppRestrictionsProvider.setTestRestrictions(policyBundle); + } + } +} diff --git a/components/policy/android/junit/src/org/chromium/policy/test/annotations/PoliciesTest.java b/components/policy/android/junit/src/org/chromium/policy/test/annotations/PoliciesTest.java new file mode 100644 index 0000000..7bc08e4 --- /dev/null +++ b/components/policy/android/junit/src/org/chromium/policy/test/annotations/PoliciesTest.java @@ -0,0 +1,94 @@ +// 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.policy.test.annotations; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.chromium.policy.test.PolicyData; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Unit tests for the {@link Policies} annotations + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class PoliciesTest { + @Test + public void testGetPolicies() throws NoSuchMethodException { + Method method; + + // Simple element, one annotation, no parent + assertThat(Policies.getPolicies(SomeClass.class).keySet(), is(makeSet("Ni"))); + + // Simple element, removing an annotation just has no effect + assertThat(Policies.getPolicies(SomeClassThatRemoves.class).isEmpty(), is(true)); + + // Simple element, adds and removes the same element: We process additions, then removals. + assertThat(Policies.getPolicies(SomeConfusedClass.class).isEmpty(), is(true)); + + // Annotations are inherited + method = SomeClass.class.getDeclaredMethod("someMethodWithoutWord"); + assertThat(Policies.getPolicies(method).keySet(), is(makeSet("Ni"))); + + // Annotations add up + method = SomeClass.class.getDeclaredMethod("someMethod"); + assertThat(Policies.getPolicies(method).keySet(), is(makeSet("Ni", "Neee-wom"))); + + // Annotations from methods are not inherited + method = SomeDerivedClass.class.getDeclaredMethod("someMethod"); + assertThat(Policies.getPolicies(method).keySet(), is(makeSet("Ni"))); + + // Annotations are properly deduped, we get the one closest to the examined element + method = SomeClass.class.getDeclaredMethod("someMethodThatDuplicates"); + Map<String, PolicyData> policies = Policies.getPolicies(method); + assertThat(policies.size(), is(1)); + assertThat(policies.get("Ni"), is(PolicyData.Str.class)); + + // Annotations can be removed + method = SomeClass.class.getDeclaredMethod("someMethodThatTilRecentlyHadNi"); + assertThat(Policies.getPolicies(method).keySet(), + is(makeSet("Ekke Ekke Ekke Ekke Ptangya Zoooooooom Boing Ni"))); + } + + private Set<String> makeSet(String... keys) { + return new HashSet<String>(Arrays.asList(keys)); + } + + @Policies.Add(@Policies.Item(key = "Ni")) + private static class SomeClass { + @SuppressWarnings("unused") + void someMethodWithoutWord() {} + + @Policies.Add(@Policies.Item(key = "Neee-wom")) + void someMethod() {} + + @Policies.Add(@Policies.Item(key = "Ni", string = "Makes it string, not undefined.")) + void someMethodThatDuplicates() {} + + @Policies.Remove(@Policies.Item(key = "Ni")) + @Policies.Add(@Policies.Item(key = "Ekke Ekke Ekke Ekke Ptangya Zoooooooom Boing Ni")) + void someMethodThatTilRecentlyHadNi() {} + } + + private static class SomeDerivedClass extends SomeClass { + @Override + void someMethod() {} + } + + @Policies.Remove(@Policies.Item(key = "Ni")) + private static class SomeClassThatRemoves {} + + @Policies.Add(@Policies.Item(key = "Ni")) + @Policies.Remove(@Policies.Item(key = "Ni")) + private static class SomeConfusedClass {} +} |