OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.net; |
| 6 |
| 7 import android.os.ConditionVariable; |
| 8 import android.os.StrictMode; |
| 9 import android.support.test.filters.SmallTest; |
| 10 |
| 11 import org.chromium.base.Log; |
| 12 import org.chromium.base.annotations.JNINamespace; |
| 13 import org.chromium.base.annotations.SuppressFBWarnings; |
| 14 import org.chromium.base.test.util.DisabledTest; |
| 15 import org.chromium.base.test.util.Feature; |
| 16 import org.chromium.base.test.util.MetricsUtils.HistogramDelta; |
| 17 import org.chromium.net.MetricsTestUtil.TestExecutor; |
| 18 import org.chromium.net.test.EmbeddedTestServer; |
| 19 |
| 20 import java.io.File; |
| 21 import java.io.FileInputStream; |
| 22 import java.io.FileNotFoundException; |
| 23 import java.io.IOException; |
| 24 import java.util.concurrent.Executor; |
| 25 import java.util.concurrent.Executors; |
| 26 import java.util.concurrent.ThreadFactory; |
| 27 |
| 28 /** |
| 29 * Test Network Quality Estimator. |
| 30 */ |
| 31 @JNINamespace("cronet") |
| 32 public class NQETest extends CronetTestBase { |
| 33 private static final String TAG = NQETest.class.getSimpleName(); |
| 34 |
| 35 private EmbeddedTestServer mTestServer; |
| 36 private String mUrl; |
| 37 |
| 38 // Thread on which network quality listeners should be notified. |
| 39 private Thread mNetworkQualityThread; |
| 40 |
| 41 @Override |
| 42 protected void setUp() throws Exception { |
| 43 super.setUp(); |
| 44 mTestServer = EmbeddedTestServer.createAndStartServer(getContext()); |
| 45 mUrl = mTestServer.getURL("/echo?status=200"); |
| 46 } |
| 47 |
| 48 private class ExecutorThreadFactory implements ThreadFactory { |
| 49 public Thread newThread(final Runnable r) { |
| 50 mNetworkQualityThread = new Thread(new Runnable() { |
| 51 @Override |
| 52 public void run() { |
| 53 StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadP
olicy(); |
| 54 try { |
| 55 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.B
uilder() |
| 56 .detectNetwork() |
| 57 .penaltyLog() |
| 58 .penaltyDeath() |
| 59 .build()); |
| 60 r.run(); |
| 61 } finally { |
| 62 StrictMode.setThreadPolicy(threadPolicy); |
| 63 } |
| 64 } |
| 65 }); |
| 66 return mNetworkQualityThread; |
| 67 } |
| 68 } |
| 69 |
| 70 @SmallTest |
| 71 @Feature({"Cronet"}) |
| 72 public void testNotEnabled() throws Exception { |
| 73 ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
| 74 new ExperimentalCronetEngine.Builder(getContext()); |
| 75 final CronetTestFramework testFramework = |
| 76 startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCro
netEngineBuilder); |
| 77 Executor networkQualityExecutor = Executors.newSingleThreadExecutor(); |
| 78 TestNetworkQualityRttListener rttListener = |
| 79 new TestNetworkQualityRttListener(networkQualityExecutor); |
| 80 TestNetworkQualityThroughputListener throughputListener = |
| 81 new TestNetworkQualityThroughputListener(networkQualityExecutor,
null); |
| 82 try { |
| 83 testFramework.mCronetEngine.addRttListener(rttListener); |
| 84 fail("Should throw an exception."); |
| 85 } catch (IllegalStateException e) { |
| 86 } |
| 87 try { |
| 88 testFramework.mCronetEngine.addThroughputListener(throughputListener
); |
| 89 fail("Should throw an exception."); |
| 90 } catch (IllegalStateException e) { |
| 91 } |
| 92 TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
| 93 UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBu
ilder( |
| 94 mUrl, callback, callback.getExecutor()); |
| 95 UrlRequest urlRequest = builder.build(); |
| 96 |
| 97 urlRequest.start(); |
| 98 callback.blockForDone(); |
| 99 assertEquals(0, rttListener.rttObservationCount()); |
| 100 assertEquals(0, throughputListener.throughputObservationCount()); |
| 101 testFramework.mCronetEngine.shutdown(); |
| 102 } |
| 103 |
| 104 @SmallTest |
| 105 @Feature({"Cronet"}) |
| 106 public void testListenerRemoved() throws Exception { |
| 107 ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
| 108 new ExperimentalCronetEngine.Builder(getContext()); |
| 109 TestExecutor networkQualityExecutor = new TestExecutor(); |
| 110 TestNetworkQualityRttListener rttListener = |
| 111 new TestNetworkQualityRttListener(networkQualityExecutor); |
| 112 mCronetEngineBuilder.enableNetworkQualityEstimator(true); |
| 113 final CronetTestFramework testFramework = |
| 114 startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCro
netEngineBuilder); |
| 115 testFramework.mCronetEngine.configureNetworkQualityEstimatorForTesting(t
rue, true, false); |
| 116 |
| 117 testFramework.mCronetEngine.addRttListener(rttListener); |
| 118 testFramework.mCronetEngine.removeRttListener(rttListener); |
| 119 TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
| 120 UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBu
ilder( |
| 121 mUrl, callback, callback.getExecutor()); |
| 122 UrlRequest urlRequest = builder.build(); |
| 123 urlRequest.start(); |
| 124 callback.blockForDone(); |
| 125 networkQualityExecutor.runAllTasks(); |
| 126 assertEquals(0, rttListener.rttObservationCount()); |
| 127 testFramework.mCronetEngine.shutdown(); |
| 128 } |
| 129 |
| 130 // Returns whether a file contains a particular string. |
| 131 @SuppressFBWarnings("OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE") |
| 132 private boolean fileContainsString(String filename, String content) throws I
OException { |
| 133 File file = |
| 134 new File(CronetTestFramework.getTestStorage(getContext()) + "/pr
efs/" + filename); |
| 135 FileInputStream fileInputStream = new FileInputStream(file); |
| 136 byte[] data = new byte[(int) file.length()]; |
| 137 fileInputStream.read(data); |
| 138 fileInputStream.close(); |
| 139 return new String(data, "UTF-8").contains(content); |
| 140 } |
| 141 |
| 142 @SmallTest |
| 143 @Feature({"Cronet"}) |
| 144 @DisabledTest(message = "Disabled due to flaky assert. See crbug.com/710626"
) |
| 145 public void testQuicDisabled() throws Exception { |
| 146 ExperimentalCronetEngine.Builder mCronetEngineBuilder = |
| 147 new ExperimentalCronetEngine.Builder(getContext()); |
| 148 assert RttThroughputValues.INVALID_RTT_THROUGHPUT < 0; |
| 149 Executor listenersExecutor = Executors.newSingleThreadExecutor(new Execu
torThreadFactory()); |
| 150 ConditionVariable waitForThroughput = new ConditionVariable(); |
| 151 TestNetworkQualityRttListener rttListener = |
| 152 new TestNetworkQualityRttListener(listenersExecutor); |
| 153 TestNetworkQualityThroughputListener throughputListener = |
| 154 new TestNetworkQualityThroughputListener(listenersExecutor, wait
ForThroughput); |
| 155 mCronetEngineBuilder.enableNetworkQualityEstimator(true).enableHttp2(tru
e).enableQuic( |
| 156 false); |
| 157 mCronetEngineBuilder.setStoragePath(CronetTestFramework.getTestStorage(g
etContext())); |
| 158 final CronetTestFramework testFramework = |
| 159 startCronetTestFrameworkWithUrlAndCronetEngineBuilder(null, mCro
netEngineBuilder); |
| 160 testFramework.mCronetEngine.configureNetworkQualityEstimatorForTesting(t
rue, true, true); |
| 161 |
| 162 testFramework.mCronetEngine.addRttListener(rttListener); |
| 163 testFramework.mCronetEngine.addThroughputListener(throughputListener); |
| 164 |
| 165 HistogramDelta writeCountHistogram = new HistogramDelta("NQE.Prefs.Write
Count", 1); |
| 166 assertEquals(0, writeCountHistogram.getDelta()); // Sanity check. |
| 167 |
| 168 HistogramDelta readCountHistogram = new HistogramDelta("NQE.Prefs.ReadCo
unt", 1); |
| 169 assertEquals(0, readCountHistogram.getDelta()); // Sanity check. |
| 170 |
| 171 TestUrlRequestCallback callback = new TestUrlRequestCallback(); |
| 172 UrlRequest.Builder builder = testFramework.mCronetEngine.newUrlRequestBu
ilder( |
| 173 mUrl, callback, callback.getExecutor()); |
| 174 UrlRequest urlRequest = builder.build(); |
| 175 urlRequest.start(); |
| 176 callback.blockForDone(); |
| 177 |
| 178 // Throughput observation is posted to the network quality estimator on
the network thread |
| 179 // after the UrlRequest is completed. The observations are then eventual
ly posted to |
| 180 // throughput listeners on the executor provided to network quality. |
| 181 waitForThroughput.block(); |
| 182 assertTrue(throughputListener.throughputObservationCount() > 0); |
| 183 |
| 184 // Prefs must be read at startup. |
| 185 assertTrue(readCountHistogram.getDelta() > 0); |
| 186 |
| 187 // Check RTT observation count after throughput observation has been rec
eived. This ensures |
| 188 // that executor has finished posting the RTT observation to the RTT lis
teners. |
| 189 assertTrue(rttListener.rttObservationCount() > 0); |
| 190 |
| 191 // NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST |
| 192 assertTrue(rttListener.rttObservationCount(0) > 0); |
| 193 |
| 194 // NETWORK_QUALITY_OBSERVATION_SOURCE_TCP |
| 195 assertTrue(rttListener.rttObservationCount(1) > 0); |
| 196 |
| 197 // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC |
| 198 assertEquals(0, rttListener.rttObservationCount(2)); |
| 199 |
| 200 // Verify that the listeners were notified on the expected thread. |
| 201 assertEquals(mNetworkQualityThread, rttListener.getThread()); |
| 202 assertEquals(mNetworkQualityThread, throughputListener.getThread()); |
| 203 |
| 204 // Verify that effective connection type callback is received and |
| 205 // effective connection type is correctly set. |
| 206 assertTrue(testFramework.mCronetEngine.getEffectiveConnectionType() |
| 207 != EffectiveConnectionType.TYPE_UNKNOWN); |
| 208 |
| 209 // Verify that the HTTP RTT, transport RTT and downstream throughput |
| 210 // estimates are available. |
| 211 assertTrue(testFramework.mCronetEngine.getHttpRttMs() >= 0); |
| 212 assertTrue(testFramework.mCronetEngine.getTransportRttMs() >= 0); |
| 213 assertTrue(testFramework.mCronetEngine.getDownstreamThroughputKbps() >=
0); |
| 214 |
| 215 // Verify that the cached estimates were written to the prefs. |
| 216 while (true) { |
| 217 Log.i(TAG, "Still waiting for pref file update....."); |
| 218 Thread.sleep(12000); |
| 219 try { |
| 220 if (fileContainsString("local_prefs.json", "network_qualities"))
{ |
| 221 break; |
| 222 } |
| 223 } catch (FileNotFoundException e) { |
| 224 // Ignored this exception since the file will only be created wh
en updates are |
| 225 // flushed to the disk. |
| 226 } |
| 227 } |
| 228 assertTrue(fileContainsString("local_prefs.json", "network_qualities")); |
| 229 |
| 230 testFramework.mCronetEngine.shutdown(); |
| 231 assertTrue(writeCountHistogram.getDelta() > 0); |
| 232 } |
| 233 } |
OLD | NEW |