Merge "Reduce DnsResolverTest flaky rate"

This commit is contained in:
Luke Huang
2020-02-21 10:23:46 +00:00
committed by Gerrit Code Review
3 changed files with 54 additions and 15 deletions

View File

@@ -86,7 +86,7 @@ public class DnsResolverTest extends AndroidTestCase {
static final int CANCEL_RETRY_TIMES = 5; static final int CANCEL_RETRY_TIMES = 5;
static final int QUERY_TIMES = 10; static final int QUERY_TIMES = 10;
static final int NXDOMAIN = 3; 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 ContentResolver mCR;
private ConnectivityManager mCM; private ConnectivityManager mCM;
@@ -122,10 +122,15 @@ public class DnsResolverTest extends AndroidTestCase {
mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER); mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
} }
private void restorePrivateDnsSetting() { private void restorePrivateDnsSetting() throws InterruptedException {
// restore private DNS setting // restore private DNS setting
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode); 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) { private static String byteArrayToHexString(byte[] bytes) {
@@ -203,6 +208,7 @@ public class DnsResolverTest extends AndroidTestCase {
private final CancellationSignal mCancelSignal; private final CancellationSignal mCancelSignal;
private int mRcode; private int mRcode;
private DnsAnswer mDnsAnswer; private DnsAnswer mDnsAnswer;
private String mErrorMsg = null;
VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
mMsg = msg; mMsg = msg;
@@ -228,14 +234,18 @@ public class DnsResolverTest extends AndroidTestCase {
@Override @Override
public void onAnswer(@NonNull byte[] answer, int rcode) { public void onAnswer(@NonNull byte[] answer, int rcode) {
if (mCancelSignal != null && mCancelSignal.isCanceled()) { 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; mRcode = rcode;
try { try {
mDnsAnswer = new DnsAnswer(answer); mDnsAnswer = new DnsAnswer(answer);
} catch (ParseException | DnsParseException e) { } catch (ParseException | DnsParseException e) {
fail(mMsg + e.getMessage()); mErrorMsg = mMsg + e.getMessage();
mLatch.countDown();
return;
} }
Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer));
mLatch.countDown(); mLatch.countDown();
@@ -243,10 +253,12 @@ public class DnsResolverTest extends AndroidTestCase {
@Override @Override
public void onError(@NonNull DnsResolver.DnsException error) { public void onError(@NonNull DnsResolver.DnsException error) {
fail(mMsg + error.getMessage()); mErrorMsg = mMsg + error.getMessage();
mLatch.countDown();
} }
private void assertValidAnswer() { private void assertValidAnswer() {
assertNull(mErrorMsg);
assertNotNull(mMsg + " No valid answer", mDnsAnswer); assertNotNull(mMsg + " No valid answer", mDnsAnswer);
assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode + assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode +
" blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode()); " blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode());
@@ -402,20 +414,18 @@ public class DnsResolverTest extends AndroidTestCase {
public void doTestRawQueryNXDomainWithPrivateDns(Executor executor) public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
throws InterruptedException { throws InterruptedException {
final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS"; 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. // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
// b/144521720 // b/144521720
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
Settings.Global.putString(mCR, Settings.Global.putString(mCR,
Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER); Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
for (Network network : getTestableNetworks()) { for (Network network : getTestableNetworks()) {
final Network networkForPrivateDns = final Network networkForPrivateDns =
(network != null) ? network : mCM.getActiveNetwork(); (network != null) ? network : mCM.getActiveNetwork();
assertNotNull("Can't find network to await private DNS on", networkForPrivateDns); assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER, networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
PRIVATE_DNS_SETTING_TIMEOUT_MS); PRIVATE_DNS_SETTING_TIMEOUT_MS, true);
final VerifyCancelCallback callback = new VerifyCancelCallback(msg); final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
executor, null, callback); executor, null, callback);
@@ -508,6 +518,7 @@ public class DnsResolverTest extends AndroidTestCase {
private final String mMsg; private final String mMsg;
private final List<InetAddress> mAnswers; private final List<InetAddress> mAnswers;
private final CancellationSignal mCancelSignal; private final CancellationSignal mCancelSignal;
private String mErrorMsg = null;
VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { VerifyCancelInetAddressCallback(@NonNull String msg, @Nullable CancellationSignal cancel) {
this.mMsg = msg; this.mMsg = msg;
@@ -541,10 +552,16 @@ public class DnsResolverTest extends AndroidTestCase {
return false; return false;
} }
public void assertNoError() {
assertNull(mErrorMsg);
}
@Override @Override
public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) { public void onAnswer(@NonNull List<InetAddress> answerList, int rcode) {
if (mCancelSignal != null && mCancelSignal.isCanceled()) { 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) { for (InetAddress addr : answerList) {
Log.d(TAG, "Reported addr: " + addr.toString()); Log.d(TAG, "Reported addr: " + addr.toString());
@@ -556,7 +573,7 @@ public class DnsResolverTest extends AndroidTestCase {
@Override @Override
public void onError(@NonNull DnsResolver.DnsException error) { public void onError(@NonNull DnsResolver.DnsException error) {
fail(mMsg + error.getMessage()); mErrorMsg = mMsg + error.getMessage();
} }
} }
@@ -601,6 +618,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
callback.waitForAnswer()); callback.waitForAnswer());
callback.assertNoError();
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
} }
} }
@@ -644,6 +662,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
callback.waitForAnswer()); callback.waitForAnswer());
callback.assertNoError();
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer());
} }
@@ -659,6 +678,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
callback.waitForAnswer()); callback.waitForAnswer());
callback.assertNoError();
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer());
} }
@@ -671,7 +691,6 @@ public class DnsResolverTest extends AndroidTestCase {
Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname"); Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
Settings.Global.putString(mCR, Settings.Global.putString(mCR,
Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER); Settings.Global.PRIVATE_DNS_SPECIFIER, INVALID_PRIVATE_DNS_SERVER);
final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN; final String msg = "Test PrivateDnsBypass " + TEST_DOMAIN;
for (Network network : testNetworks) { for (Network network : testNetworks) {
// This test cannot be ran with null network because we need to explicitly pass a // This test cannot be ran with null network because we need to explicitly pass a
@@ -680,7 +699,7 @@ public class DnsResolverTest extends AndroidTestCase {
// wait for private DNS setting propagating // wait for private DNS setting propagating
mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout", 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 CountDownLatch latch = new CountDownLatch(1);
final DnsResolver.Callback<List<InetAddress>> errorCallback = final DnsResolver.Callback<List<InetAddress>> errorCallback =
@@ -712,6 +731,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.", assertTrue(msg + " bypass private DNS round. No answer after " + TIMEOUT_MS + "ms.",
callback.waitForAnswer()); callback.waitForAnswer());
callback.assertNoError();
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
// To ensure private DNS bypass still work even if passing null network. // To ensure private DNS bypass still work even if passing null network.
@@ -724,6 +744,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " with null network bypass private DNS round. No answer after " + assertTrue(msg + " with null network bypass private DNS round. No answer after " +
TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer()); TIMEOUT_MS + "ms.", callbackWithNullNetwork.waitForAnswer());
callbackWithNullNetwork.assertNoError();
assertTrue(msg + " with null network returned 0 results", assertTrue(msg + " with null network returned 0 results",
!callbackWithNullNetwork.isAnswerEmpty()); !callbackWithNullNetwork.isAnswerEmpty());
@@ -745,6 +766,7 @@ public class DnsResolverTest extends AndroidTestCase {
assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
callback.waitForAnswer()); callback.waitForAnswer());
callback.assertNoError();
assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty());
assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results", assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results",
queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer()); queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer());

View File

@@ -245,7 +245,7 @@ public class MultinetworkApiTest extends AndroidTestCase {
for (Network network : getTestableNetworks()) { for (Network network : getTestableNetworks()) {
// Wait for private DNS setting to propagate. // Wait for private DNS setting to propagate.
mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout", 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()); runResNnxDomainCheck(network.getNetworkHandle());
} }
} finally { } finally {

View File

@@ -56,6 +56,7 @@ public final class CtsNetUtils {
private static final String TAG = CtsNetUtils.class.getSimpleName(); private static final String TAG = CtsNetUtils.class.getSimpleName();
private static final int DURATION = 10000; private static final int DURATION = 10000;
private static final int SOCKET_TIMEOUT_MS = 2000; 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 int HTTP_PORT = 80;
public static final String TEST_HOST = "connectivitycheck.gstatic.com"; public static final String TEST_HOST = "connectivitycheck.gstatic.com";
@@ -246,12 +247,16 @@ public final class CtsNetUtils {
} }
public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, 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); CountDownLatch latch = new CountDownLatch(1);
NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
NetworkCallback callback = new NetworkCallback() { NetworkCallback callback = new NetworkCallback() {
@Override @Override
public void onLinkPropertiesChanged(Network n, LinkProperties lp) { public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
if (requiresValidatedServers && lp.getValidatedPrivateDnsServers().isEmpty()) {
return;
}
if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
latch.countDown(); latch.countDown();
} }
@@ -260,6 +265,18 @@ public final class CtsNetUtils {
mCm.registerNetworkCallback(request, callback); mCm.registerNetworkCallback(request, callback);
assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS)); assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
mCm.unregisterNetworkCallback(callback); 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);
}
} }
/** /**