Index: components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java |
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4bf2631d5e9c845980ca4b7d0be57cc8aeba9dc5 |
--- /dev/null |
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/NQETest.java |
@@ -0,0 +1,233 @@ |
+// Copyright 2017 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.net; |
+ |
+import android.os.ConditionVariable; |
+import android.os.StrictMode; |
+import android.support.test.filters.SmallTest; |
+ |
+import org.chromium.base.Log; |
+import org.chromium.base.annotations.JNINamespace; |
+import org.chromium.base.annotations.SuppressFBWarnings; |
+import org.chromium.base.test.util.DisabledTest; |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta; |
+import org.chromium.net.MetricsTestUtil.TestExecutor; |
+import org.chromium.net.test.EmbeddedTestServer; |
+ |
+import java.io.File; |
+import java.io.FileInputStream; |
+import java.io.FileNotFoundException; |
+import java.io.IOException; |
+import java.util.concurrent.Executor; |
+import java.util.concurrent.Executors; |
+import java.util.concurrent.ThreadFactory; |
+ |
+/** |
+ * Test Network Quality Estimator. |
+ */ |
+@JNINamespace("cronet") |
+public class NQETest extends CronetTestBase { |
+ private static final String TAG = NQETest.class.getSimpleName(); |
+ |
+ private EmbeddedTestServer mTestServer; |
+ private String mUrl; |
+ |
+ // Thread on which network quality listeners should be notified. |
+ private Thread mNetworkQualityThread; |
+ |
+ @Override |
+ protected void setUp() throws Exception { |
+ super.setUp(); |
+ mTestServer = EmbeddedTestServer.createAndStartServer(getContext()); |
+ mUrl = mTestServer.getURL("/echo?status=200"); |
+ } |
+ |
+ private class ExecutorThreadFactory implements ThreadFactory { |
+ public Thread newThread(final Runnable r) { |
+ mNetworkQualityThread = new Thread(new Runnable() { |
+ @Override |
+ public void run() { |
+ StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadPolicy(); |
+ try { |
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() |
+ .detectNetwork() |
+ .penaltyLog() |
+ .penaltyDeath() |
+ .build()); |
+ r.run(); |
+ } finally { |
+ StrictMode.setThreadPolicy(threadPolicy); |
+ } |
+ } |
+ }); |
+ return mNetworkQualityThread; |
+ } |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Cronet"}) |
+ public void testNotEnabled() throws Exception { |
+ ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
+ new ExperimentalCronetEngine.Builder(getContext()); |
+ final CronetTestFramework testFramework = |
+ startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCronetEngineBuilder); |
+ Executor networkQualityExecutor = Executors.newSingleThreadExecutor(); |
+ TestNetworkQualityRttListener rttListener = |
+ new TestNetworkQualityRttListener(networkQualityExecutor); |
+ TestNetworkQualityThroughputListener throughputListener = |
+ new TestNetworkQualityThroughputListener(networkQualityExecutor, null); |
+ try { |
+ testFramework.mCronetEngine.addRttListener(rttListener); |
+ fail("Should throw an exception."); |
+ } catch (IllegalStateException e) { |
+ } |
+ try { |
+ testFramework.mCronetEngine.addThroughputListener(throughputListener); |
+ fail("Should throw an exception."); |
+ } catch (IllegalStateException e) { |
+ } |
+ TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
+ UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBuilder( |
+ mUrl, callback, callback.getExecutor()); |
+ UrlRequest urlRequest = builder.build(); |
+ |
+ urlRequest.start(); |
+ callback.blockForDone(); |
+ assertEquals(0, rttListener.rttObservationCount()); |
+ assertEquals(0, throughputListener.throughputObservationCount()); |
+ testFramework.mCronetEngine.shutdown(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Cronet"}) |
+ public void testListenerRemoved() throws Exception { |
+ ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
+ new ExperimentalCronetEngine.Builder(getContext()); |
+ TestExecutor networkQualityExecutor = new TestExecutor(); |
+ TestNetworkQualityRttListener rttListener = |
+ new TestNetworkQualityRttListener(networkQualityExecutor); |
+ mCronetEngineBuilder.enableNetworkQualityEstimator(true); |
+ final CronetTestFramework testFramework = |
+ startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCronetEngineBuilder); |
+ testFramework.mCronetEngine.configureNetworkQualityEstimatorForTesting(true, true, false); |
+ |
+ testFramework.mCronetEngine.addRttListener(rttListener); |
+ testFramework.mCronetEngine.removeRttListener(rttListener); |
+ TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
+ UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBuilder( |
+ mUrl, callback, callback.getExecutor()); |
+ UrlRequest urlRequest = builder.build(); |
+ urlRequest.start(); |
+ callback.blockForDone(); |
+ networkQualityExecutor.runAllTasks(); |
+ assertEquals(0, rttListener.rttObservationCount()); |
+ testFramework.mCronetEngine.shutdown(); |
+ } |
+ |
+ // Returns whether a file contains a particular string. |
+ @SuppressFBWarnings("OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE") |
+ private boolean fileContainsString(String filename, String content) throws IOException { |
+ File file = |
+ new File(CronetTestFramework.getTestStorage(getContext()) + "/prefs/" + filename); |
+ FileInputStream fileInputStream = new FileInputStream(file); |
+ byte[] data = new byte[(int) file.length()]; |
+ fileInputStream.read(data); |
+ fileInputStream.close(); |
+ return new String(data, "UTF-8").contains(content); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Cronet"}) |
+ @DisabledTest(message = "Disabled due to flaky assert. See crbug.com/710626") |
+ public void testQuicDisabled() throws Exception { |
+ ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
+ new ExperimentalCronetEngine.Builder(getContext()); |
+ assert RttThroughputValues.INVALID_RTT_THROUGHPUT < 0; |
+ Executor listenersExecutor = Executors.newSingleThreadExecutor(new ExecutorThreadFactory()); |
+ ConditionVariable waitForThroughput = new ConditionVariable(); |
+ TestNetworkQualityRttListener rttListener = |
+ new TestNetworkQualityRttListener(listenersExecutor); |
+ TestNetworkQualityThroughputListener throughputListener = |
+ new TestNetworkQualityThroughputListener(listenersExecutor, waitForThroughput); |
+ mCronetEngineBuilder.enableNetworkQualityEstimator(true).enableHttp2(true).enableQuic( |
+ false); |
+ mCronetEngineBuilder.setStoragePath(CronetTestFramework.getTestStorage(getContext())); |
+ final CronetTestFramework testFramework = |
+ startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCronetEngineBuilder); |
+ testFramework.mCronetEngine.configureNetworkQualityEstimatorForTesting(true, true, true); |
+ |
+ testFramework.mCronetEngine.addRttListener(rttListener); |
+ testFramework.mCronetEngine.addThroughputListener(throughputListener); |
+ |
+ HistogramDelta writeCountHistogram = new HistogramDelta("NQE.Prefs.WriteCount", 1); |
+ assertEquals(0, writeCountHistogram.getDelta()); // Sanity check. |
+ |
+ HistogramDelta readCountHistogram = new HistogramDelta("NQE.Prefs.ReadCount", 1); |
+ assertEquals(0, readCountHistogram.getDelta()); // Sanity check. |
+ |
+ TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
+ UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBuilder( |
+ mUrl, callback, callback.getExecutor()); |
+ UrlRequest urlRequest = builder.build(); |
+ urlRequest.start(); |
+ callback.blockForDone(); |
+ |
+ // Throughput observation is posted to the network quality estimator on the network thread |
+ // after the UrlRequest is completed. The observations are then eventually posted to |
+ // throughput listeners on the executor provided to network quality. |
+ waitForThroughput.block(); |
+ assertTrue(throughputListener.throughputObservationCount() > 0); |
+ |
+ // Prefs must be read at startup. |
+ assertTrue(readCountHistogram.getDelta() > 0); |
+ |
+ // Check RTT observation count after throughput observation has been received. This ensures |
+ // that executor has finished posting the RTT observation to the RTT listeners. |
+ assertTrue(rttListener.rttObservationCount() > 0); |
+ |
+ // NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST |
+ assertTrue(rttListener.rttObservationCount(0) > 0); |
+ |
+ // NETWORK_QUALITY_OBSERVATION_SOURCE_TCP |
+ assertTrue(rttListener.rttObservationCount(1) > 0); |
+ |
+ // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC |
+ assertEquals(0, rttListener.rttObservationCount(2)); |
+ |
+ // Verify that the listeners were notified on the expected thread. |
+ assertEquals(mNetworkQualityThread, rttListener.getThread()); |
+ assertEquals(mNetworkQualityThread, throughputListener.getThread()); |
+ |
+ // Verify that effective connection type callback is received and |
+ // effective connection type is correctly set. |
+ assertTrue(testFramework.mCronetEngine.getEffectiveConnectionType() |
+ != EffectiveConnectionType.TYPE_UNKNOWN); |
+ |
+ // Verify that the HTTP RTT, transport RTT and downstream throughput |
+ // estimates are available. |
+ assertTrue(testFramework.mCronetEngine.getHttpRttMs() >= 0); |
+ assertTrue(testFramework.mCronetEngine.getTransportRttMs() >= 0); |
+ assertTrue(testFramework.mCronetEngine.getDownstreamThroughputKbps() >= 0); |
+ |
+ // Verify that the cached estimates were written to the prefs. |
+ while (true) { |
+ Log.i(TAG, "Still waiting for pref file update....."); |
+ Thread.sleep(12000); |
+ try { |
+ if (fileContainsString("local_prefs.json", "network_qualities")) { |
+ break; |
+ } |
+ } catch (FileNotFoundException e) { |
+ // Ignored this exception since the file will only be created when updates are |
+ // flushed to the disk. |
+ } |
+ } |
+ assertTrue(fileContainsString("local_prefs.json", "network_qualities")); |
+ |
+ testFramework.mCronetEngine.shutdown(); |
+ assertTrue(writeCountHistogram.getDelta() > 0); |
+ } |
+} |