Merge "Cts tests for multiple CA Certificates for WifiEnterpriseConfig."
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java
new file mode 100644
index 0000000..5d3812c
--- /dev/null
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnectivityManagerTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.net.hostside;
+
+import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
+import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
+import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
+import android.app.Activity;
+import android.net.ConnectivityManager;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+/**
+ * Tests for the {@link ConnectivityManager} API.
+ *
+ * <p>These tests rely on a host-side test to use {@code adb shell cmd netpolicy} to put the device
+ * in the proper state. In fact, they're more like "assertions" than tests per se - the real test
+ * logic is done on {@code HostsideNetworkTests}.
+ */
+public class ConnectivityManagerTest extends InstrumentationTestCase {
+    private static final String TAG = "ConnectivityManagerTest";
+
+    private ConnectivityManager mCM;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mCM = (ConnectivityManager) getInstrumentation().getContext().getSystemService(
+                Activity.CONNECTIVITY_SERVICE);
+    }
+
+    public void testGetRestrictBackgroundStatus_disabled() {
+        assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+    }
+
+    public void testGetRestrictBackgroundStatus_whitelisted() {
+        assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
+    }
+
+    public void testGetRestrictBackgroundStatus_enabled() {
+        assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
+    }
+
+    private void assertRestrictBackgroundStatus(int expectedStatus) {
+        final String expected = toString(expectedStatus);
+        Log.d(TAG, getName() + " (expecting " + expected + ")");
+        final int actualStatus = mCM.getRestrictBackgroundStatus();
+        assertEquals("wrong status", expected, toString(actualStatus));
+    }
+
+    private String toString(int status) {
+        switch (status) {
+            case RESTRICT_BACKGROUND_STATUS_DISABLED:
+                return "DISABLED";
+            case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+                return "WHITELISTED";
+            case RESTRICT_BACKGROUND_STATUS_ENABLED:
+                return "ENABLED";
+            default:
+                return "UNKNOWN_STATUS_" + status;
+        }
+    }
+}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java
index f42de0e..dd2424c 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTests.java
@@ -17,6 +17,7 @@
 package com.android.cts.net;
 
 import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -24,17 +25,20 @@
 import com.android.ddmlib.testrunner.TestRunResult;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.CollectingTestListener;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
 import com.android.tradefed.testtype.IBuildReceiver;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.result.CollectingTestListener;
 
+import java.io.FileNotFoundException;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class HostsideNetworkTests extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "HostsideNetworkTests";
     private static final String TEST_PKG = "com.android.cts.net.hostside";
     private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk";
 
@@ -58,28 +62,130 @@
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
-        getDevice().uninstallPackage(TEST_PKG);
-
-        assertNull(getDevice().installPackage(
-            MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+        setRestrictBackground(false);
+        uninstallTestPackage(false);
+        installTestPackage();
     }
 
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
 
-        getDevice().uninstallPackage(TEST_PKG);
+        uninstallTestPackage(false);
+        setRestrictBackground(false);
     }
 
     public void testVpn() throws Exception {
-        runDeviceTests(TEST_PKG, ".VpnTest");
+        runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest");
+    }
+
+    public void testConnectivityManager_getRestrictBackgroundStatus_disabled() throws Exception {
+        final int uid = getUid(TEST_PKG);
+        removeRestrictBackgroundWhitelist(uid);
+        assertRestrictBackgroundStatusDisabled();
+        // Sanity check: make sure status is always disabled, never whitelisted
+        addRestrictBackgroundWhitelist(uid);
+        assertRestrictBackgroundStatusDisabled();
+    }
+
+    public void testConnectivityManager_getRestrictBackgroundStatus_whitelisted() throws Exception {
+        final int uid = getUid(TEST_PKG);
+        setRestrictBackground(true);
+        addRestrictBackgroundWhitelist(uid);
+        assertRestrictBackgroundStatusWhitelisted();
+    }
+
+    public void testConnectivityManager_getRestrictBackgroundStatus_enabled() throws Exception {
+        final int uid = getUid(TEST_PKG);
+        setRestrictBackground(true);
+        removeRestrictBackgroundWhitelist(uid);
+        assertRestrictBackgroundStatusEnabled();
+    }
+
+    public void testConnectivityManager_getRestrictBackgroundStatus_uninstall() throws Exception {
+        final int uid = getUid(TEST_PKG);
+
+        addRestrictBackgroundWhitelist(uid);
+        assertRestrictBackgroundWhitelist(uid, true);
+
+        uninstallTestPackage(true);
+        assertPackageUninstalled(TEST_PKG);
+        assertRestrictBackgroundWhitelist(uid, false);
+
+        installTestPackage();
+        final int newUid = getUid(TEST_PKG);
+        assertRestrictBackgroundWhitelist(uid, false);
+        assertRestrictBackgroundWhitelist(newUid, false);
+    }
+
+    private void installTestPackage() throws DeviceNotAvailableException, FileNotFoundException {
+        assertNull(getDevice().installPackage(
+                MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+    }
+
+    private void uninstallTestPackage(boolean shouldSucceed) throws DeviceNotAvailableException {
+        final String result = getDevice().uninstallPackage(TEST_PKG);
+        if (shouldSucceed) {
+            assertNull("uninstallPackage failed: " + result, result);
+        }
+    }
+
+    private void assertPackageUninstalled(String packageName) throws DeviceNotAvailableException {
+        final String command = "cmd package list packages -f " + packageName;
+        final int max_tries = 5;
+        for (int i = 1; i <= max_tries; i++) {
+            final String result = runCommand(command);
+            if (result.trim().isEmpty()) {
+                return;
+            }
+            i++;
+            Log.v(TAG, "Package " + packageName + " not uninstalled yet (" + result
+                    + "); sleeping 1s before polling again");
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+        }
+        fail("Package '" + packageName + "' not uinstalled after " + max_tries + " seconds");
+    }
+
+    private void assertRestrictBackgroundStatusDisabled() throws DeviceNotAvailableException {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
+                "testGetRestrictBackgroundStatus_disabled");
+    }
+
+    private void assertRestrictBackgroundStatusWhitelisted() throws DeviceNotAvailableException {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
+                "testGetRestrictBackgroundStatus_whitelisted");
+    }
+
+    private void assertRestrictBackgroundStatusEnabled() throws DeviceNotAvailableException {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".ConnectivityManagerTest",
+                "testGetRestrictBackgroundStatus_enabled");
     }
 
     public void runDeviceTests(String packageName, String testClassName)
-           throws DeviceNotAvailableException {
+            throws DeviceNotAvailableException {
+        runDeviceTests(packageName, testClassName, null);
+    }
+
+    public void runDeviceTests(String packageName, String testClassName, String methodName)
+            throws DeviceNotAvailableException {
         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
                 "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice());
 
+        if (testClassName != null) {
+            // TODO: figure out why testRunner.setMethodName() / testRunner.setClassName() doesn't
+            // work
+            final StringBuilder runOptions = new StringBuilder("-e class ").append(testClassName);
+            if (methodName != null) {
+                runOptions.append('#').append(methodName);
+            }
+            Log.i(TAG, "Setting runOptions() as " + runOptions);
+            testRunner.setRunOptions(runOptions.toString());
+        }
+
         final CollectingTestListener listener = new CollectingTestListener();
         getDevice().runInstrumentationTests(testRunner, listener);
 
@@ -103,4 +209,57 @@
             throw new AssertionError(errorBuilder.toString());
         }
     }
+
+    private static final Pattern UID_PATTERN =
+            Pattern.compile(".*userId=([0-9]+)$", Pattern.MULTILINE);
+
+    private int getUid(String packageName) throws DeviceNotAvailableException {
+        final String output = runCommand("dumpsys package " + packageName);
+        final Matcher matcher = UID_PATTERN.matcher(output);
+        while (matcher.find()) {
+            final String match = matcher.group(1);
+            return Integer.parseInt(match);
+        }
+        throw new RuntimeException("Did not find regexp '" + UID_PATTERN + "' on adb output\n"
+                + output);
+    }
+
+    private void addRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException {
+        runCommand("cmd netpolicy add restrict-background-whitelist " + uid);
+        assertRestrictBackgroundWhitelist(uid, true);
+    }
+
+    private void removeRestrictBackgroundWhitelist(int uid) throws DeviceNotAvailableException {
+        runCommand("cmd netpolicy remove restrict-background-whitelist " + uid);
+        assertRestrictBackgroundWhitelist(uid, false);
+    }
+
+    private void assertRestrictBackgroundWhitelist(int uid, boolean expected)
+            throws DeviceNotAvailableException {
+        final String output = runCommand("cmd netpolicy list restrict-background-whitelist ");
+        // TODO: use MoreAsserts
+        if (expected) {
+            assertTrue("Did not find uid '" + uid + "' on '" + output + "'",
+                    output.contains(Integer.toString(uid)));
+        } else {
+            assertFalse("Found uid '" + uid + "' on '" + output + "'",
+                    output.contains(Integer.toString(uid)));
+        }
+    }
+
+    private void setRestrictBackground(boolean enabled) throws DeviceNotAvailableException {
+        runCommand("cmd netpolicy set restrict-background " + enabled);
+        final String output = runCommand("cmd netpolicy get restrict-background ").trim();
+        final String expectedSuffix = enabled ? "enabled" : "disabled";
+        // TODO: use MoreAsserts?
+        assertTrue("output '" + output + "' should end with '" + expectedSuffix + "'",
+                output.endsWith(expectedSuffix));
+    }
+
+    private String runCommand(String command) throws DeviceNotAvailableException {
+        Log.d(TAG, "Command: '" + command + "'");
+        final String output = getDevice().executeShellCommand(command);
+        if (DEBUG) Log.v(TAG, "Output: " + output.trim());
+        return output;
+    }
 }
diff --git a/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java b/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
index 16d3ac4..5e2a55e 100644
--- a/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
+++ b/tests/cts/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
@@ -107,7 +107,7 @@
     public void testGetCns_whitespace() {
         assertCns("cn= p", "p");
         assertCns("cn=\np", "p");
-        assertCns("cn=\tp", "p");
+        assertCns("cn=\tp", "\tp");
     }
 
     public void testGetCnsWithOid() {