Merge "Enable verbose logging for the test app."
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
index cedd62a..5ecb399 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DumpOnFailureRule.java
@@ -16,6 +16,7 @@
 package com.android.cts.net.hostside;
 
 import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TAG;
+import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_APP2_PKG;
 import static com.android.cts.net.hostside.AbstractRestrictBackgroundNetworkTestCase.TEST_PKG;
 
 import android.os.Environment;
@@ -58,7 +59,7 @@
             for (String cmd : new String[] {
                     "dumpsys netpolicy",
                     "dumpsys network_management",
-                    "dumpsys usagestats " + TEST_PKG,
+                    "dumpsys usagestats " + TEST_PKG + " " + TEST_APP2_PKG,
                     "dumpsys usagestats appstandby",
             }) {
                 dumpCommandOutput(out, cmd);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
new file mode 100644
index 0000000..0a80047
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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 static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.NetworkRequest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityDiagnosticsManagerTest {
+    private static final Executor INLINE_EXECUTOR = x -> x.run();
+    private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build();
+
+    private Context mContext;
+    private ConnectivityDiagnosticsManager mCdm;
+    private ConnectivityDiagnosticsCallback mCallback;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class);
+
+        mCallback = new ConnectivityDiagnosticsCallback() {};
+    }
+
+    @Test
+    public void testRegisterConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+    }
+
+    @Test
+    public void testRegisterDuplicateConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+
+        try {
+            mCdm.registerConnectivityDiagnosticsCallback(
+                    DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+            fail("Registering the same callback twice should throw an IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testUnregisterConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+        mCdm.unregisterConnectivityDiagnosticsCallback(mCallback);
+    }
+
+    @Test
+    public void testUnregisterUnknownConnectivityDiagnosticsCallback() {
+        // Expected to silently ignore the unregister() call
+        mCdm.unregisterConnectivityDiagnosticsCallback(mCallback);
+    }
+}
diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
index c32a7a0..1cc49f9 100644
--- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java
@@ -86,7 +86,7 @@
     static final int CANCEL_RETRY_TIMES = 5;
     static final int QUERY_TIMES = 10;
     static final int NXDOMAIN = 3;
-    static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
+    static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
 
     private ContentResolver mCR;
     private ConnectivityManager mCM;
@@ -122,10 +122,15 @@
         mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
     }
 
-    private void restorePrivateDnsSetting() {
+    private void restorePrivateDnsSetting() throws InterruptedException {
         // restore private DNS setting
         Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
-        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
+        if ("hostname".equals(mOldMode)) {
+            Settings.Global.putString(
+                mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
+            mCtsNetUtils.awaitPrivateDnsSetting("restorePrivateDnsSetting timeout",
+                    mCM.getActiveNetwork(), mOldDnsSpecifier, PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
+        }
     }
 
     private static String byteArrayToHexString(byte[] bytes) {
@@ -203,6 +208,7 @@
         private final CancellationSignal mCancelSignal;
         private int mRcode;
         private DnsAnswer mDnsAnswer;
+        private String mErrorMsg = null;
 
         VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
             mMsg = msg;
@@ -228,14 +234,18 @@
         @Override
         public void onAnswer(@NonNull byte[] answer, int rcode) {
             if (mCancelSignal != null && mCancelSignal.isCanceled()) {
-                fail(mMsg + " should not have returned any answers");
+                mErrorMsg = mMsg + " should not have returned any answers";
+                mLatch.countDown();
+                return;
             }
 
             mRcode = rcode;
             try {
                 mDnsAnswer = new DnsAnswer(answer);
             } catch (ParseException | DnsParseException e) {
-                fail(mMsg + e.getMessage());
+                mErrorMsg = mMsg + e.getMessage();
+                mLatch.countDown();
+                return;
             }
             Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
             mLatch.countDown();
@@ -243,10 +253,12 @@
 
         @Override
         public void onError(@NonNull DnsResolver.DnsException error) {
-            fail(mMsg + error.getMessage());
+            mErrorMsg = mMsg + error.getMessage();
+            mLatch.countDown();
         }
 
         private void assertValidAnswer() {
+            assertNull(mErrorMsg);
             assertNotNull(mMsg + " No valid answer", mDnsAnswer);
             assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode +
                     " blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode());
@@ -402,20 +414,18 @@
     public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
             throws InterruptedException {
         final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS";
-
         // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
         // b/144521720
         Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
         Settings.Global.putString(mCR,
                 Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
-
         for (Network network :  getTestableNetworks()) {
             final Network networkForPrivateDns =
                     (network != null) ? network : mCM.getActiveNetwork();
             assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
             mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
                     networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
-                    PRIVATE_DNS_SETTING_TIMEOUT_MS);
+                    PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
             mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
                     executor, null, callback);
@@ -508,6 +518,7 @@
         private final String mMsg;
         private final List<InetAddress> mAnswers;
         private final CancellationSignal mCancelSignal;
+        private String mErrorMsg = null;
 
         VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
             this.mMsg = msg;
@@ -541,10 +552,16 @@
             return false;
         }
 
+        public void assertNoError() {
+            assertNull(mErrorMsg);
+        }
+
         @Override
         public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
             if (mCancelSignal != null && mCancelSignal.isCanceled()) {
-                fail(mMsg + " should not have returned any answers");
+                mErrorMsg = mMsg + " should not have returned any answers";
+                mLatch.countDown();
+                return;
             }
             for (InetAddress addr : answerList) {
                 Log.d(TAG, "Reported addr: " + addr.toString());
@@ -556,7 +573,7 @@
 
         @Override
         public void onError(@NonNull DnsResolver.DnsException error) {
-            fail(mMsg + error.getMessage());
+            mErrorMsg = mMsg + error.getMessage();
         }
     }
 
@@ -601,6 +618,7 @@
 
             assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
                     callback.waitForAnswer());
+            callback.assertNoError();
             assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
         }
     }
@@ -644,6 +662,7 @@
 
             assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
                     callback.waitForAnswer());
+            callback.assertNoError();
             assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
             assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
         }
@@ -659,6 +678,7 @@
 
             assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
                     callback.waitForAnswer());
+            callback.assertNoError();
             assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
             assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
         }
@@ -671,7 +691,6 @@
         Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
         Settings.Global.putString(mCR,
                 Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER);
-
         final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN;
         for (Network network : testNetworks) {
             // This test cannot be ran with null network because we need to explicitly pass a
@@ -680,7 +699,7 @@
 
             // wait for private DNS setting propagating
             mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
-                    network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
+                    network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, false);
 
             final CountDownLatch latch = new CountDownLatch(1);
             final DnsResolver.Callback<List<InetAddress>> errorCallback =
@@ -712,6 +731,7 @@
 
             assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.",
                     callback.waitForAnswer());
+            callback.assertNoError();
             assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
 
             // To ensure private DNS bypass still work even if passing null network.
@@ -724,6 +744,7 @@
 
             assertTrue(msg + " with null network bypass private DNS round. No answer after " +
                     TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer());
+            callbackWithNullNetwork.assertNoError();
             assertTrue(msg + " with null network returned 0 results",
                     !callbackWithNullNetwork.isAnswerEmpty());
 
@@ -745,6 +766,7 @@
 
                 assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
                         callback.waitForAnswer());
+                callback.assertNoError();
                 assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
                 assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results",
                         queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer());
diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
index 766c55e..f123187 100644
--- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
@@ -245,7 +245,7 @@
             for (Network network : getTestableNetworks()) {
               // Wait for private DNS setting to propagate.
               mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
-                        network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
+                        network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
               runResNnxDomainCheck(network.getNetworkHandle());
             }
         } finally {
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
index e4c4b00..45b9d97 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
@@ -16,17 +16,15 @@
 
 package android.net.wifi.cts;
 
-import android.content.Context;
+import static com.google.common.truth.Truth.assertThat;
+
 import android.content.pm.PackageManager;
 import android.net.wifi.WifiEnterpriseConfig;
 import android.net.wifi.WifiEnterpriseConfig.Eap;
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
-import android.net.wifi.WifiManager;
 import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
-import com.android.compatibility.common.util.SystemUtil;
-
 import java.io.ByteArrayInputStream;
 import java.security.KeyFactory;
 import java.security.PrivateKey;
@@ -36,9 +34,7 @@
 
 @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 public class WifiEnterpriseConfigTest extends AndroidTestCase {
-    private WifiManager mWifiManager;
 
-    private static final String SSID = "\"TestSSID\"";
     private static final String IDENTITY = "identity";
     private static final String PASSWORD = "password";
     private static final String SUBJECT_MATCH = "subjectmatch";
@@ -47,7 +43,11 @@
     private static final String PLMN = "plmn";
     private static final String REALM = "realm";
     private static final String ANON_IDENTITY = "anonidentity";
-    private static final int ENABLE_DELAY = 10000;
+    private static final String CERTIFICATE_ALIAS1 = "certificatealias1";
+    private static final String CERTIFICATE_ALIAS2 = "certificatealias2";
+    private static final String CA_PATH = "capath";
+    private static final String CLIENT_CERTIFICATE_ALIAS = "clientcertificatealias";
+    private static final String WAPI_CERT_SUITE = "wapicertsuite";
 
     /*
      * The keys and certificates below are generated with:
@@ -684,22 +684,6 @@
                 PackageManager.FEATURE_WIFI);
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        if(!hasWifi()) {
-            return;
-        }
-        mWifiManager = (WifiManager) mContext
-                .getSystemService(Context.WIFI_SERVICE);
-        assertNotNull(mWifiManager);
-        SystemUtil.runShellCommand("svc wifi enable");
-        Thread.sleep(ENABLE_DELAY);
-        if (hasWifi()) {
-            assertTrue(mWifiManager.isWifiEnabled());
-        }
-    }
-
     public void testSettersAndGetters() throws Exception {
         if (!hasWifi()) {
             return;
@@ -766,6 +750,7 @@
         assertTrue(testClientCertChain.length == 2);
         assertTrue(testClientCertChain[0] == testClientCert);
         assertTrue(testClientCertChain[1] == cert1);
+        assertSame(clientKey, config.getClientPrivateKey());
 
         config.setSubjectMatch(SUBJECT_MATCH);
         assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH));
@@ -793,4 +778,122 @@
         assertTrue(stringRepresentation.contains(identity));
         assertFalse(stringRepresentation.contains(password));
     }
+
+    public void testGetSetCaCertificateAliases() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setCaCertificateAliases(null);
+        assertThat(config.getCaCertificateAliases()).isNull();
+
+        config.setCaCertificateAliases(new String[]{CERTIFICATE_ALIAS1});
+        assertThat(config.getCaCertificateAliases()).isEqualTo(new String[]{CERTIFICATE_ALIAS1});
+
+        config.setCaCertificateAliases(new String[]{CERTIFICATE_ALIAS1, CERTIFICATE_ALIAS2});
+        assertThat(config.getCaCertificateAliases())
+                .isEqualTo(new String[]{CERTIFICATE_ALIAS1, CERTIFICATE_ALIAS2});
+    }
+
+    public void testGetSetCaPath() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setCaPath("");
+        assertThat(config.getCaPath()).isEmpty();
+
+        config.setCaPath(CA_PATH);
+        assertThat(config.getCaPath()).isEqualTo(CA_PATH);
+    }
+
+    public void testGetSetClientCertificateAlias() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setClientCertificateAlias("");
+        assertThat(config.getClientCertificateAlias()).isEmpty();
+
+        config.setClientCertificateAlias(CLIENT_CERTIFICATE_ALIAS);
+        assertThat(config.getClientCertificateAlias()).isEqualTo(CLIENT_CERTIFICATE_ALIAS);
+    }
+
+    public void testGetSetOcsp() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setOcsp(WifiEnterpriseConfig.OCSP_NONE);
+        assertThat(config.getOcsp()).isEqualTo(WifiEnterpriseConfig.OCSP_NONE);
+
+        config.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
+        assertThat(config.getOcsp())
+                .isEqualTo(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
+
+        try {
+            config.setOcsp(-1);
+            fail("WifiEnterpriseConfig.setOcsp(-1) did not throw an IllegalArgumentException!");
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    public void testGetSetWapiCertSuite() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setWapiCertSuite("");
+        assertThat(config.getWapiCertSuite()).isEmpty();
+
+        config.setWapiCertSuite(WAPI_CERT_SUITE);
+        assertThat(config.getWapiCertSuite()).isEqualTo(WAPI_CERT_SUITE);
+    }
+
+    public void testIsAuthenticationSimBased() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+
+        config.setEapMethod(Eap.AKA);
+        assertThat(config.isAuthenticationSimBased()).isTrue();
+
+        config.setEapMethod(Eap.PWD);
+        assertThat(config.isAuthenticationSimBased()).isFalse();
+
+        config.setEapMethod(Eap.PEAP);
+        config.setPhase2Method(Phase2.SIM);
+        assertThat(config.isAuthenticationSimBased()).isTrue();
+
+        config.setEapMethod(Eap.PEAP);
+        config.setPhase2Method(Phase2.NONE);
+        assertThat(config.isAuthenticationSimBased()).isFalse();
+    }
+
+    public void testCopyConstructor() {
+        if (!hasWifi()) {
+            return;
+        }
+        WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+        config.setEapMethod(Eap.WAPI_CERT);
+        config.setWapiCertSuite(WAPI_CERT_SUITE);
+        config.setOcsp(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
+        config.setCaPath(CA_PATH);
+        config.setPassword(PASSWORD);
+        config.setRealm(REALM);
+
+        WifiEnterpriseConfig copy = new WifiEnterpriseConfig(config);
+        assertThat(copy.getEapMethod()).isEqualTo(Eap.WAPI_CERT);
+        assertThat(copy.getWapiCertSuite()).isEqualTo(WAPI_CERT_SUITE);
+        assertThat(copy.getOcsp())
+                .isEqualTo(WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS);
+        assertThat(copy.getCaPath()).isEqualTo(CA_PATH);
+        assertThat(copy.getPassword()).isEqualTo(PASSWORD);
+        assertThat(copy.getRealm()).isEqualTo(REALM);
+    }
 }
diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java
index d943231..6f94fea 100644
--- a/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java
+++ b/tests/cts/net/src/android/net/wifi/cts/WifiInfoTest.java
@@ -16,11 +16,13 @@
 
 package android.net.wifi.cts;
 
+import static com.google.common.truth.Truth.assertThat;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.wifi.ScanResult;
 import android.net.wifi.SupplicantState;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
@@ -78,13 +80,13 @@
 
         mContext.registerReceiver(mReceiver, mIntentFilter);
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
-        assertNotNull(mWifiManager);
+        assertThat(mWifiManager).isNotNull();
         mWifiLock = mWifiManager.createWifiLock(TAG);
         mWifiLock.acquire();
         if (!mWifiManager.isWifiEnabled())
             setWifiEnabled(true);
         Thread.sleep(DURATION);
-        assertTrue(mWifiManager.isWifiEnabled());
+        assertThat(mWifiManager.isWifiEnabled()).isTrue();
         mMySync.expectedState = STATE_NULL;
     }
 
@@ -123,31 +125,19 @@
             // skip the test if WiFi is not supported
             return;
         }
+
+        // wait for Wifi to be connected
+        PollingCheck.check(
+                "Wifi not connected - Please ensure there is a saved network in range of this "
+                        + "device",
+                20000,
+                () -> mWifiManager.getConnectionInfo().getNetworkId() != -1);
+
         // this test case should in Wifi environment
         WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
 
-        assertNotNull(wifiInfo);
-        assertNotNull(wifiInfo.toString());
-        SupplicantState.isValidState(wifiInfo.getSupplicantState());
-        WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED);
-        String ssid = wifiInfo.getSSID();
-        if (!ssid.startsWith("0x") && !ssid.equals(WifiManager.UNKNOWN_SSID)) {
-            // Non-hex string should be quoted
-            assertTrue(ssid.charAt(0) == '"');
-            assertTrue(ssid.charAt(ssid.length() - 1) == '"');
-        }
+        testWifiInfoPropertiesWhileConnected(wifiInfo);
 
-        wifiInfo.getBSSID();
-        wifiInfo.getFrequency();
-        wifiInfo.getIpAddress();
-        wifiInfo.getLinkSpeed();
-        wifiInfo.getPasspointFqdn();
-        wifiInfo.getPasspointProviderFriendlyName();
-        wifiInfo.getTxLinkSpeedMbps();
-        wifiInfo.getRxLinkSpeedMbps();
-        wifiInfo.getRssi();
-        wifiInfo.getHiddenSSID();
-        wifiInfo.getMacAddress();
         setWifiEnabled(false);
 
         PollingCheck.check("getNetworkId not -1", 20000, new Callable<Boolean>() {
@@ -166,4 +156,55 @@
         });
     }
 
+    private void testWifiInfoPropertiesWhileConnected(WifiInfo wifiInfo) {
+        assertThat(wifiInfo).isNotNull();
+        assertThat(wifiInfo.toString()).isNotNull();
+        SupplicantState.isValidState(wifiInfo.getSupplicantState());
+        WifiInfo.getDetailedStateOf(SupplicantState.DISCONNECTED);
+        String ssid = wifiInfo.getSSID();
+        if (!ssid.startsWith("0x") && !ssid.equals(WifiManager.UNKNOWN_SSID)) {
+            // Non-hex string should be quoted
+            assertThat(ssid).startsWith("\"");
+            assertThat(ssid).endsWith("\"");
+        }
+
+        assertThat(wifiInfo.getBSSID()).isNotNull();
+        assertThat(wifiInfo.getFrequency()).isGreaterThan(0);
+        assertThat(wifiInfo.getMacAddress()).isNotNull();
+
+        wifiInfo.getRssi();
+        wifiInfo.getIpAddress();
+        wifiInfo.getHiddenSSID();
+        wifiInfo.getScore();
+
+        // null for saved networks
+        assertThat(wifiInfo.getRequestingPackageName()).isNull();
+        assertThat(wifiInfo.getPasspointFqdn()).isNull();
+        assertThat(wifiInfo.getPasspointProviderFriendlyName()).isNull();
+
+        // false for saved networks
+        assertThat(wifiInfo.isEphemeral()).isFalse();
+        assertThat(wifiInfo.isOsuAp()).isFalse();
+        assertThat(wifiInfo.isPasspointAp()).isFalse();
+
+        assertThat(wifiInfo.getWifiStandard()).isAnyOf(
+                ScanResult.WIFI_STANDARD_UNKNOWN,
+                ScanResult.WIFI_STANDARD_LEGACY,
+                ScanResult.WIFI_STANDARD_11N,
+                ScanResult.WIFI_STANDARD_11AC,
+                ScanResult.WIFI_STANDARD_11AX
+        );
+
+        assertThat(wifiInfo.getLostTxPacketsPerSecond()).isAtLeast(0.0);
+        assertThat(wifiInfo.getRetriedTxPacketsPerSecond()).isAtLeast(0.0);
+        assertThat(wifiInfo.getSuccessfulRxPacketsPerSecond()).isAtLeast(0.0);
+        assertThat(wifiInfo.getSuccessfulTxPacketsPerSecond()).isAtLeast(0.0);
+
+        // Can be -1 if link speed is unknown
+        assertThat(wifiInfo.getLinkSpeed()).isAtLeast(-1);
+        assertThat(wifiInfo.getTxLinkSpeedMbps()).isAtLeast(-1);
+        assertThat(wifiInfo.getRxLinkSpeedMbps()).isAtLeast(-1);
+        assertThat(wifiInfo.getMaxSupportedTxLinkSpeedMbps()).isAtLeast(-1);
+        assertThat(wifiInfo.getMaxSupportedRxLinkSpeedMbps()).isAtLeast(-1);
+    }
 }
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index f0c34e3..6214f89 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -56,6 +56,7 @@
     private static final String TAG = CtsNetUtils.class.getSimpleName();
     private static final int DURATION = 10000;
     private static final int SOCKET_TIMEOUT_MS = 2000;
+    private static final int PRIVATE_DNS_PROBE_MS = 1_000;
 
     public static final int HTTP_PORT = 80;
     public static final String TEST_HOST = "connectivitycheck.gstatic.com";
@@ -246,12 +247,16 @@
     }
 
     public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
-            @NonNull String server, int timeoutMs) throws InterruptedException {
+            @NonNull String server, int timeoutMs,
+            boolean requiresValidatedServers) throws InterruptedException {
         CountDownLatch latch = new CountDownLatch(1);
         NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
         NetworkCallback callback = new NetworkCallback() {
             @Override
             public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
+                if (requiresValidatedServers && lp.getValidatedPrivateDnsServers().isEmpty()) {
+                    return;
+                }
                 if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
                     latch.countDown();
                 }
@@ -260,6 +265,18 @@
         mCm.registerNetworkCallback(request, callback);
         assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
         mCm.unregisterNetworkCallback(callback);
+        // Wait some time for NetworkMonitor's private DNS probe to complete. If we do not do
+        // this, then the test could complete before the NetworkMonitor private DNS probe
+        // completes. This would result in tearDown disabling private DNS, and the NetworkMonitor
+        // private DNS probe getting stuck because there are no longer any private DNS servers to
+        // query. This then results in the next test not being able to change the private DNS
+        // setting within the timeout, because the NetworkMonitor thread is blocked in the
+        // private DNS probe. There is no way to know when the probe has completed: because the
+        // network is likely already validated, there is no callback that we can listen to, so
+        // just sleep.
+        if (requiresValidatedServers) {
+            Thread.sleep(PRIVATE_DNS_PROBE_MS);
+        }
     }
 
     /**