Merge "Skip data saver related tests if the device doesn't support it." into oc-dev
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index 2fc0bc2..0f2965c 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -143,6 +143,8 @@
         assertBackgroundNetworkAccess(true);
         setBatterySaverMode(true);
         assertBackgroundNetworkAccess(false);
+        // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger
+        setBatterySaverMode(false);
         turnBatteryOn();
         assertBackgroundNetworkAccess(true);
 
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 42eb321..b6857ae 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -716,9 +716,9 @@
         Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
         if (enabled) {
             turnBatteryOff();
-            executeSilentShellCommand("settings put global low_power 1");
+            executeSilentShellCommand("cmd power set-mode 1");
         } else {
-            executeSilentShellCommand("settings put global low_power 0");
+            executeSilentShellCommand("cmd power set-mode 0");
             turnBatteryOn();
         }
     }
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 24871ca..83f087b 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -45,12 +45,15 @@
 
 import com.android.internal.telephony.PhoneConstants;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.Socket;
 import java.net.InetSocketAddress;
 import java.util.HashMap;
+import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -74,6 +77,17 @@
             "Host: " + TEST_HOST + "\r\n" +
             "Connection: keep-alive\r\n\r\n";
 
+    // Base path for IPv6 sysctls
+    private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf";
+
+    // Expected values for MIN|MAX_PLEN.
+    private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN = 48;
+    private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN = 64;
+
+    // Expected values for RFC 7559 router soliciations.
+    // Maximum number of router solicitations to send. -1 means no limit.
+    private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1;
+
     // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
     private static final String NETWORK_CALLBACK_ACTION =
             "ConnectivityManagerTest.NetworkCallbackAction";
@@ -91,6 +105,7 @@
     private PackageManager mPackageManager;
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
+    boolean mWifiConnectAttempted;
 
     @Override
     protected void setUp() throws Exception {
@@ -99,6 +114,7 @@
         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mPackageManager = mContext.getPackageManager();
+        mWifiConnectAttempted = false;
 
         // Get com.android.internal.R.array.networkAttributes
         int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
@@ -116,6 +132,27 @@
         }
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        // Return WiFi to its original disabled state after tests that explicitly connect.
+        if (mWifiConnectAttempted) {
+            disconnectFromWifi(null);
+        }
+    }
+
+    /**
+     * Make sure WiFi is connected to an access point if it is not already. If
+     * WiFi is enabled as a result of this function, it will be disabled
+     * automatically in tearDown().
+     */
+    private Network ensureWifiConnected() {
+        if (mWifiManager.isWifiEnabled()) {
+            return getWifiNetwork();
+        }
+        mWifiConnectAttempted = true;
+        return connectToWifi();
+    }
+
     public void testIsNetworkTypeValid() {
         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
@@ -298,14 +335,10 @@
         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
 
-        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
         Network wifiNetwork = null;
 
         try {
-            // Make sure WiFi is connected to an access point to start with.
-            if (!previousWifiEnabledState) {
-                connectToWifi();
-            }
+            ensureWifiConnected();
 
             // Now we should expect to get a network callback about availability of the wifi
             // network even if it was already connected as a state-based action when the callback
@@ -321,11 +354,6 @@
         } finally {
             mCm.unregisterNetworkCallback(callback);
             mCm.unregisterNetworkCallback(defaultTrackingCallback);
-
-            // Return WiFi to its original enabled/disabled state.
-            if (!previousWifiEnabledState) {
-                disconnectFromWifi(wifiNetwork);
-            }
         }
     }
 
@@ -357,13 +385,8 @@
         // We will register for a WIFI network being available or lost.
         mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
 
-        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
-
         try {
-            // Make sure WiFi is connected to an access point to start with.
-            if (!previousWifiEnabledState) {
-                connectToWifi();
-            }
+            ensureWifiConnected();
 
             // Now we expect to get the Intent delivered notifying of the availability of the wifi
             // network even if it was already connected as a state-based action when the callback
@@ -376,11 +399,6 @@
             mCm.unregisterNetworkCallback(pendingIntent);
             pendingIntent.cancel();
             mContext.unregisterReceiver(receiver);
-
-            // Return WiFi to its original enabled/disabled state.
-            if (!previousWifiEnabledState) {
-                disconnectFromWifi(null);
-            }
         }
     }
 
@@ -761,4 +779,42 @@
             fail("No exception thrown when restricted network requested.");
         } catch (SecurityException expected) {}
     }
+
+    private Scanner makeWifiSysctlScanner(String key) throws FileNotFoundException {
+        Network network = ensureWifiConnected();
+        String iface = mCm.getLinkProperties(network).getInterfaceName();
+        String path = IPV6_SYSCTL_DIR + "/" + iface + "/" + key;
+        return new Scanner(new File(path));
+    }
+
+    /** Verify that accept_ra_rt_info_min_plen exists and is set to the expected value */
+    public void testAcceptRaRtInfoMinPlen() throws Exception {
+        Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_min_plen");
+        assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN, s.nextInt());
+    }
+
+    /** Verify that accept_ra_rt_info_max_plen exists and is set to the expected value */
+    public void testAcceptRaRtInfoMaxPlen() throws Exception {
+        Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_max_plen");
+        assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN, s.nextInt());
+    }
+
+    /** Verify that router_solicitations exists and is set to the expected value */
+    public void testRouterSolicitations() throws Exception {
+        Scanner s = makeWifiSysctlScanner("router_solicitations");
+        assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, s.nextInt());
+    }
+
+    /** Verify that router_solicitation_max_interval exists and is in an acceptable interval */
+    public void testRouterSolicitationMaxInterval() throws Exception {
+        Scanner s = makeWifiSysctlScanner("router_solicitation_max_interval");
+        int interval = s.nextInt();
+        // Verify we're in the interval [15 minutes, 60 minutes]. Lower values may adversely
+        // impact battery life and higher values can decrease the probability of detecting
+        // network changes.
+        final int lowerBoundSec = 15 * 60;
+        final int upperBoundSec = 60 * 60;
+        assertTrue(lowerBoundSec <= interval);
+        assertTrue(interval <= upperBoundSec);
+    }
 }
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
new file mode 100644
index 0000000..39d683d
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 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 android.net.cts;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.IpSecAlgorithm;
+import android.net.IpSecManager;
+import android.net.IpSecTransform;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+public class IpSecManagerTest extends AndroidTestCase {
+
+    private static final String TAG = IpSecManagerTest.class.getSimpleName();
+
+    private IpSecManager mISM;
+
+    private ConnectivityManager mCM;
+
+    private static final InetAddress GOOGLE_DNS_4;
+    private static final InetAddress GOOGLE_DNS_6;
+
+    static {
+        try {
+            // Google Public DNS Addresses;
+            GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
+            GOOGLE_DNS_6 = InetAddress.getByName("2001:4860:4860::8888");
+        } catch (UnknownHostException e) {
+            throw new RuntimeException("Could not resolve DNS Addresses", e);
+        }
+    }
+
+    private static final InetAddress[] GOOGLE_DNS_LIST =
+            new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6};
+
+    private static final int DROID_SPI = 0xD1201D;
+
+    private static final byte[] CRYPT_KEY =
+            new byte[] {
+                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+                0x0E, 0x0F
+            };
+    private static final byte[] AUTH_KEY =
+            new byte[] {
+                0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x7F
+            };
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE);
+    }
+
+    /*
+     * Allocate a random SPI
+     * Allocate a specific SPI using previous randomly created SPI value
+     * Realloc the same SPI that was specifically created (expect SpiUnavailable)
+     * Close SPIs
+     */
+    public void testAllocSpi() throws Exception {
+        for (InetAddress addr : GOOGLE_DNS_LIST) {
+            IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
+            randomSpi =
+                    mISM.reserveSecurityParameterIndex(
+                            IpSecTransform.DIRECTION_OUT,
+                            addr);
+            assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+
+            droidSpi =
+                    mISM.reserveSecurityParameterIndex(
+                            IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
+            assertTrue(droidSpi.getSpi() == DROID_SPI);
+
+            try {
+                mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
+                fail("Duplicate SPI was allowed to be created");
+            } catch (IpSecManager.SpiUnavailableException expected) {
+                // This is a success case because we expect a dupe SPI to throw
+            }
+
+            randomSpi.close();
+            droidSpi.close();
+        }
+    }
+
+    /*
+     * Alloc outbound SPI
+     * Alloc inbound SPI
+     * Create transport mode transform
+     * open socket
+     * apply transform to socket
+     * send data on socket
+     * release transform
+     * send data (expect exception)
+     */
+    public void testCreateTransform() throws Exception {
+        InetAddress local = InetAddress.getLoopbackAddress();
+        IpSecManager.SecurityParameterIndex outSpi =
+                mISM.reserveSecurityParameterIndex(
+                        IpSecTransform.DIRECTION_OUT,
+                        local);
+
+        IpSecManager.SecurityParameterIndex inSpi =
+                mISM.reserveSecurityParameterIndex(
+                        IpSecTransform.DIRECTION_IN, local, outSpi.getSpi());
+
+        IpSecTransform transform =
+                new IpSecTransform.Builder(mContext)
+                        .setSpi(IpSecTransform.DIRECTION_OUT, outSpi)
+                        .setEncryption(
+                                IpSecTransform.DIRECTION_OUT,
+                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
+                        .setAuthentication(
+                                IpSecTransform.DIRECTION_OUT,
+                                new IpSecAlgorithm(
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
+                                        AUTH_KEY,
+                                        AUTH_KEY.length * 8))
+                        .setSpi(IpSecTransform.DIRECTION_IN, inSpi)
+                        .setEncryption(
+                                IpSecTransform.DIRECTION_IN,
+                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
+                        .setAuthentication(
+                                IpSecTransform.DIRECTION_IN,
+                                new IpSecAlgorithm(
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
+                                        AUTH_KEY,
+                                        CRYPT_KEY.length * 8))
+                        .buildTransportModeTransform(local);
+
+        DatagramSocket localSocket;
+        localSocket = new DatagramSocket(8888);
+
+        localSocket.setSoTimeout(500);
+        mISM.applyTransportModeTransform(localSocket, transform);
+        byte[] data = new String("Best test data ever!").getBytes("UTF-8");
+
+        DatagramPacket out = new DatagramPacket(data, data.length, local, 8888);
+        localSocket.send(out);
+        DatagramPacket in = new DatagramPacket(new byte[data.length], data.length);
+
+        localSocket.receive(in);
+        Log.d(TAG, Arrays.toString(data));
+        Log.d(TAG, Arrays.toString(in.getData()));
+        assertTrue(Arrays.equals(data, in.getData()));
+        transform.close();
+        try {
+            localSocket.send(out);
+        } catch (IOException e) {
+        }
+
+        mISM.removeTransportModeTransform(localSocket, transform);
+    }
+}
diff --git a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index 1f7b31b..e134b46 100644
--- a/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/cts/net/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -257,6 +257,23 @@
          * be queued.
          */
         boolean waitForCallback(int callback) {
+            return waitForCallback(callback, WAIT_FOR_AWARE_CHANGE_SECS);
+        }
+
+        /**
+         * Wait for the specified callback - any of the ON_* constants. Returns a true
+         * on success (specified callback triggered) or false on failure (timed-out or
+         * interrupted while waiting for the requested callback).
+         *
+         * Same as waitForCallback(int callback) execpt that allows specifying a custom timeout.
+         * The default timeout is a short value expected to be sufficient for all behaviors which
+         * should happen relatively quickly. Specifying a custom timeout should only be done for
+         * those cases which are known to take a specific longer period of time.
+         *
+         * Note: other callbacks happening while while waiting for the specified callback will
+         * be queued.
+         */
+        boolean waitForCallback(int callback, int timeoutSec) {
             synchronized (mLocalLock) {
                 boolean found = mCallbackQueue.remove(callback);
                 if (found) {
@@ -268,7 +285,7 @@
             }
 
             try {
-                return mBlocker.await(WAIT_FOR_AWARE_CHANGE_SECS, TimeUnit.SECONDS);
+                return mBlocker.await(timeoutSec, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 return false;
             }
@@ -521,6 +538,46 @@
     }
 
     /**
+     * Validate that publish with a Time To Live (TTL) setting expires within the specified
+     * time (and validates that the terminate callback is triggered).
+     */
+    public void testPublishLimitedTtlSuccess() {
+        if (!TestUtils.shouldTestWifiAware(getContext())) {
+            return;
+        }
+
+        final String serviceName = "ValidName";
+        final int ttlSec = 5;
+
+        WifiAwareSession session = attachAndGetSession();
+
+        PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(
+                serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build();
+        DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest();
+
+        // 1. publish
+        session.publish(publishConfig, discoveryCb, mHandler);
+        assertTrue("Publish started",
+                discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_PUBLISH_STARTED));
+        PublishDiscoverySession discoverySession = discoveryCb.getPublishDiscoverySession();
+        assertNotNull("Publish session", discoverySession);
+
+        // 2. wait for terminate within 'ttlSec'.
+        assertTrue("Publish terminated",
+                discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED,
+                        ttlSec + 5));
+
+        // 3. try update post-termination: should time-out waiting for cb
+        publishConfig = new PublishConfig.Builder().setServiceName(
+                serviceName).setServiceSpecificInfo("extras".getBytes()).build();
+        discoverySession.updatePublish(publishConfig);
+        assertFalse("Publish update post terminate", discoveryCb.waitForCallback(
+                DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED));
+
+        session.destroy();
+    }
+
+    /**
      * Validate a successful subscribe discovery session lifetime: subscribe, update subscribe,
      * destroy.
      */
@@ -565,6 +622,46 @@
     }
 
     /**
+     * Validate that subscribe with a Time To Live (TTL) setting expires within the specified
+     * time (and validates that the terminate callback is triggered).
+     */
+    public void testSubscribeLimitedTtlSuccess() {
+        if (!TestUtils.shouldTestWifiAware(getContext())) {
+            return;
+        }
+
+        final String serviceName = "ValidName";
+        final int ttlSec = 5;
+
+        WifiAwareSession session = attachAndGetSession();
+
+        SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(
+                serviceName).setTtlSec(ttlSec).setTerminateNotificationEnabled(true).build();
+        DiscoverySessionCallbackTest discoveryCb = new DiscoverySessionCallbackTest();
+
+        // 1. subscribe
+        session.subscribe(subscribeConfig, discoveryCb, mHandler);
+        assertTrue("Subscribe started",
+                discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SUBSCRIBE_STARTED));
+        SubscribeDiscoverySession discoverySession = discoveryCb.getSubscribeDiscoverySession();
+        assertNotNull("Subscribe session", discoverySession);
+
+        // 2. wait for terminate within 'ttlSec'.
+        assertTrue("Subscribe terminated",
+                discoveryCb.waitForCallback(DiscoverySessionCallbackTest.ON_SESSION_TERMINATED,
+                        ttlSec + 5));
+
+        // 3. try update post-termination: should time-out waiting for cb
+        subscribeConfig = new SubscribeConfig.Builder().setServiceName(
+                serviceName).setServiceSpecificInfo("extras".getBytes()).build();
+        discoverySession.updateSubscribe(subscribeConfig);
+        assertFalse("Subscribe update post terminate", discoveryCb.waitForCallback(
+                DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED));
+
+        session.destroy();
+    }
+
+    /**
      * Test the send message flow. Since testing single device cannot send to a real peer -
      * validate that sending to a bogus peer fails.
      */
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
index f05ff82..14ae1b4 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -587,6 +587,10 @@
     private PasspointConfiguration generatePasspointConfig(Credential credential) {
         PasspointConfiguration config = new PasspointConfiguration();
         config.setCredential(credential);
+        // Setting update identifier to indicate R2 configuration, to avoid CA
+        // certificate being verified, since we're using a fake CA certificate
+        // for testing.
+        config.setUpdateIdentifier(1);
 
         // Setup HomeSp.
         HomeSp homeSp = new HomeSp();
@@ -656,22 +660,26 @@
      * @param config The configuration to test with
      */
     private void testAddPasspointConfig(PasspointConfiguration config) throws Exception {
-        mWifiManager.addOrUpdatePasspointConfiguration(config);
+        try {
+            mWifiManager.addOrUpdatePasspointConfiguration(config);
 
-        // Certificates and keys will be set to null after it is installed to the KeyStore by
-        // WifiManager.  Reset them in the expected config so that it can be used to compare
-        // against the retrieved config.
-        config.getCredential().setCaCertificate(null);
-        config.getCredential().setClientCertificateChain(null);
-        config.getCredential().setClientPrivateKey(null);
+            // Certificates and keys will be set to null after it is installed to the KeyStore by
+            // WifiManager.  Reset them in the expected config so that it can be used to compare
+            // against the retrieved config.
+            config.getCredential().setCaCertificate(null);
+            config.getCredential().setClientCertificateChain(null);
+            config.getCredential().setClientPrivateKey(null);
 
-        // Retrieve the configuration and verify it.
-        List<PasspointConfiguration> configList = mWifiManager.getPasspointConfigurations();
-        assertEquals(1, configList.size());
-        assertEquals(config, configList.get(0));
+            // Retrieve the configuration and verify it.
+            List<PasspointConfiguration> configList = mWifiManager.getPasspointConfigurations();
+            assertEquals(1, configList.size());
+            assertEquals(config, configList.get(0));
 
-        // Remove the configuration and verify no installed configuration.
-        mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn());
-        assertTrue(mWifiManager.getPasspointConfigurations().isEmpty());
+            // Remove the configuration and verify no installed configuration.
+            mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn());
+            assertTrue(mWifiManager.getPasspointConfigurations().isEmpty());
+        } catch (UnsupportedOperationException e) {
+            // Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop.
+        }
     }
 }