• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
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 static com.google.common.truth.Truth.assertThat;
8 import static com.google.common.truth.Truth.assertWithMessage;
9 
10 import static org.junit.Assert.assertThrows;
11 
12 import android.os.ConditionVariable;
13 
14 import androidx.test.ext.junit.runners.AndroidJUnit4;
15 import androidx.test.filters.SmallTest;
16 
17 import org.junit.After;
18 import org.junit.Before;
19 import org.junit.Rule;
20 import org.junit.Test;
21 import org.junit.runner.RunWith;
22 
23 import org.chromium.base.test.util.DoNotBatch;
24 import org.chromium.net.CronetTestRule.CronetImplementation;
25 import org.chromium.net.CronetTestRule.IgnoreFor;
26 import org.chromium.net.CronetTestRule.RequiresMinApi;
27 import org.chromium.net.MetricsTestUtil.TestExecutor;
28 import org.chromium.net.impl.CronetMetrics;
29 
30 import java.util.ArrayList;
31 import java.util.Date;
32 import java.util.List;
33 import java.util.concurrent.Executor;
34 import java.util.concurrent.RejectedExecutionException;
35 import java.util.concurrent.atomic.AtomicBoolean;
36 
37 /** Test RequestFinishedInfo.Listener and the metrics information it provides. */
38 @DoNotBatch(reason = "crbug/1459563")
39 @RunWith(AndroidJUnit4.class)
40 @IgnoreFor(
41         implementations = {CronetImplementation.FALLBACK, CronetImplementation.AOSP_PLATFORM},
42         reason = "Fallback and AOSP implementations do not support RequestFinishedListeners")
43 public class RequestFinishedInfoTest {
44     @Rule public final CronetTestRule mTestRule = CronetTestRule.withAutomaticEngineStartup();
45 
46     private String mUrl;
47 
48     // A subclass of TestRequestFinishedListener to additionally assert that UrlRequest.Callback's
49     // terminal callbacks have been invoked at the time of onRequestFinished().
50     // See crbug.com/710877.
51     private static class AssertCallbackDoneRequestFinishedListener
52             extends TestRequestFinishedListener {
53         private final TestUrlRequestCallback mCallback;
54 
AssertCallbackDoneRequestFinishedListener(TestUrlRequestCallback callback)55         public AssertCallbackDoneRequestFinishedListener(TestUrlRequestCallback callback) {
56             // Use same executor as request callback to verify stable call order.
57             super(callback.getExecutor());
58             mCallback = callback;
59         }
60 
61         @Override
onRequestFinished(RequestFinishedInfo requestInfo)62         public void onRequestFinished(RequestFinishedInfo requestInfo) {
63             assertThat(mCallback.isDone()).isTrue();
64             super.onRequestFinished(requestInfo);
65         }
66     }
67     ;
68 
69     @Before
setUp()70     public void setUp() throws Exception {
71         NativeTestServer.startNativeTestServer(mTestRule.getTestFramework().getContext());
72         mUrl = NativeTestServer.getFileURL("/echo?status=200");
73     }
74 
75     @After
tearDown()76     public void tearDown() throws Exception {
77         NativeTestServer.shutdownNativeTestServer();
78     }
79 
80     static class DirectExecutor implements Executor {
81         private ConditionVariable mBlock = new ConditionVariable();
82 
83         @Override
execute(Runnable task)84         public void execute(Runnable task) {
85             task.run();
86             mBlock.open();
87         }
88 
blockUntilDone()89         public void blockUntilDone() {
90             mBlock.block();
91         }
92     }
93 
94     static class ThreadExecutor implements Executor {
95         private List<Thread> mThreads = new ArrayList<Thread>();
96 
97         @Override
execute(Runnable task)98         public void execute(Runnable task) {
99             Thread newThread = new Thread(task);
100             mThreads.add(newThread);
101             newThread.start();
102         }
103 
joinAll()104         public void joinAll() throws InterruptedException {
105             for (Thread thread : mThreads) {
106                 thread.join();
107             }
108         }
109     }
110 
111     @Test
112     @SmallTest
113     @SuppressWarnings("deprecation")
testRequestFinishedListener()114     public void testRequestFinishedListener() throws Exception {
115         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
116         mTestRule
117                 .getTestFramework()
118                 .getEngine()
119                 .addRequestFinishedListener(requestFinishedListener);
120         TestUrlRequestCallback callback = new TestUrlRequestCallback();
121         ExperimentalUrlRequest.Builder urlRequestBuilder =
122                 (ExperimentalUrlRequest.Builder)
123                         mTestRule
124                                 .getTestFramework()
125                                 .getEngine()
126                                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
127         Date startTime = new Date();
128         urlRequestBuilder
129                 .addRequestAnnotation("request annotation")
130                 .addRequestAnnotation(this)
131                 .build()
132                 .start();
133         callback.blockForDone();
134         requestFinishedListener.blockUntilDone();
135         Date endTime = new Date();
136 
137         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
138         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
139         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
140         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
141         assertThat(requestInfo.getAnnotations()).containsExactly("request annotation", this);
142     }
143 
144     @Test
145     @SmallTest
146     @SuppressWarnings("deprecation")
testRequestFinishedListenerDirectExecutor()147     public void testRequestFinishedListenerDirectExecutor() throws Exception {
148         DirectExecutor testExecutor = new DirectExecutor();
149         TestRequestFinishedListener requestFinishedListener =
150                 new TestRequestFinishedListener(testExecutor);
151         mTestRule
152                 .getTestFramework()
153                 .getEngine()
154                 .addRequestFinishedListener(requestFinishedListener);
155         TestUrlRequestCallback callback = new TestUrlRequestCallback();
156         ExperimentalUrlRequest.Builder urlRequestBuilder =
157                 (ExperimentalUrlRequest.Builder)
158                         mTestRule
159                                 .getTestFramework()
160                                 .getEngine()
161                                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
162         Date startTime = new Date();
163         urlRequestBuilder
164                 .addRequestAnnotation("request annotation")
165                 .addRequestAnnotation(this)
166                 .build()
167                 .start();
168         callback.blockForDone();
169         // Block on the executor, not the listener, since blocking on the listener doesn't work when
170         // it's created with a non-default executor.
171         testExecutor.blockUntilDone();
172         Date endTime = new Date();
173 
174         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
175         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
176         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
177         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
178         assertThat(requestInfo.getAnnotations()).containsExactly("request annotation", this);
179     }
180 
181     @Test
182     @SmallTest
183     @SuppressWarnings("deprecation")
testRequestFinishedListenerDifferentThreads()184     public void testRequestFinishedListenerDifferentThreads() throws Exception {
185         TestRequestFinishedListener firstListener = new TestRequestFinishedListener();
186         TestRequestFinishedListener secondListener = new TestRequestFinishedListener();
187         mTestRule.getTestFramework().getEngine().addRequestFinishedListener(firstListener);
188         mTestRule.getTestFramework().getEngine().addRequestFinishedListener(secondListener);
189         TestUrlRequestCallback callback = new TestUrlRequestCallback();
190         ExperimentalUrlRequest.Builder urlRequestBuilder =
191                 (ExperimentalUrlRequest.Builder)
192                         mTestRule
193                                 .getTestFramework()
194                                 .getEngine()
195                                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
196         Date startTime = new Date();
197         urlRequestBuilder
198                 .addRequestAnnotation("request annotation")
199                 .addRequestAnnotation(this)
200                 .build()
201                 .start();
202         callback.blockForDone();
203         firstListener.blockUntilDone();
204         secondListener.blockUntilDone();
205         Date endTime = new Date();
206 
207         RequestFinishedInfo firstRequestInfo = firstListener.getRequestInfo();
208         RequestFinishedInfo secondRequestInfo = secondListener.getRequestInfo();
209 
210         MetricsTestUtil.checkRequestFinishedInfo(firstRequestInfo, mUrl, startTime, endTime);
211         assertThat(firstRequestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
212         MetricsTestUtil.checkHasConnectTiming(
213                 firstRequestInfo.getMetrics(), startTime, endTime, false);
214 
215         MetricsTestUtil.checkRequestFinishedInfo(secondRequestInfo, mUrl, startTime, endTime);
216         assertThat(secondRequestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
217         MetricsTestUtil.checkHasConnectTiming(
218                 secondRequestInfo.getMetrics(), startTime, endTime, false);
219 
220         assertThat(firstRequestInfo.getAnnotations()).containsExactly("request annotation", this);
221         assertThat(secondRequestInfo.getAnnotations()).containsExactly("request annotation", this);
222     }
223 
224     @Test
225     @SmallTest
226     @SuppressWarnings("deprecation")
testRequestFinishedListenerFailedRequest()227     public void testRequestFinishedListenerFailedRequest() throws Exception {
228         String connectionRefusedUrl = "http://127.0.0.1:3";
229         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
230         mTestRule
231                 .getTestFramework()
232                 .getEngine()
233                 .addRequestFinishedListener(requestFinishedListener);
234         TestUrlRequestCallback callback = new TestUrlRequestCallback();
235         UrlRequest.Builder urlRequestBuilder =
236                 mTestRule
237                         .getTestFramework()
238                         .getEngine()
239                         .newUrlRequestBuilder(
240                                 connectionRefusedUrl, callback, callback.getExecutor());
241         Date startTime = new Date();
242         urlRequestBuilder.build().start();
243         callback.blockForDone();
244         assertThat(callback.mOnErrorCalled).isTrue();
245         requestFinishedListener.blockUntilDone();
246         Date endTime = new Date();
247 
248         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
249         assertWithMessage("RequestFinishedInfo.Listener must be called")
250                 .that(requestInfo)
251                 .isNotNull();
252         assertThat(requestInfo.getUrl()).isEqualTo(connectionRefusedUrl);
253         assertThat(requestInfo.getAnnotations()).isEmpty();
254         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.FAILED);
255         assertThat(requestInfo.getException()).isNotNull();
256         assertThat(((NetworkException) requestInfo.getException()).getErrorCode())
257                 .isEqualTo(NetworkException.ERROR_CONNECTION_REFUSED);
258         RequestFinishedInfo.Metrics metrics = requestInfo.getMetrics();
259         assertWithMessage("RequestFinishedInfo.getMetrics() must not be null")
260                 .that(metrics)
261                 .isNotNull();
262         // The failure is occasionally fast enough that time reported is 0, so just check for null
263         assertThat(metrics.getTotalTimeMs()).isNotNull();
264         assertThat(metrics.getTtfbMs()).isNull();
265 
266         // Check the timing metrics
267         assertThat(metrics.getRequestStart()).isNotNull();
268         MetricsTestUtil.assertAfter(metrics.getRequestStart(), startTime);
269         MetricsTestUtil.checkNoConnectTiming(metrics);
270         assertThat(metrics.getSendingStart()).isNull();
271         assertThat(metrics.getSendingEnd()).isNull();
272         assertThat(metrics.getResponseStart()).isNull();
273         assertThat(metrics.getRequestEnd()).isNotNull();
274         MetricsTestUtil.assertAfter(endTime, metrics.getRequestEnd());
275         MetricsTestUtil.assertAfter(metrics.getRequestEnd(), metrics.getRequestStart());
276         assertThat(metrics.getSentByteCount()).isEqualTo(0);
277         assertThat(metrics.getReceivedByteCount()).isEqualTo(0);
278     }
279 
280     @Test
281     @SmallTest
testRequestFinishedListenerThrowInTerminalCallback()282     public void testRequestFinishedListenerThrowInTerminalCallback() throws Exception {
283         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
284         mTestRule
285                 .getTestFramework()
286                 .getEngine()
287                 .addRequestFinishedListener(requestFinishedListener);
288         TestUrlRequestCallback callback = new TestUrlRequestCallback();
289         callback.setFailure(
290                 TestUrlRequestCallback.FailureType.THROW_SYNC,
291                 TestUrlRequestCallback.ResponseStep.ON_SUCCEEDED);
292         mTestRule
293                 .getTestFramework()
294                 .getEngine()
295                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor())
296                 .build()
297                 .start();
298         callback.blockForDone();
299         requestFinishedListener.blockUntilDone();
300     }
301 
302     @Test
303     @SmallTest
testRequestFinishedListenerThrowInListener()304     public void testRequestFinishedListenerThrowInListener() throws Exception {
305         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
306         requestFinishedListener.makeListenerThrow();
307         TestUrlRequestCallback callback = new TestUrlRequestCallback();
308         mTestRule
309                 .getTestFramework()
310                 .getEngine()
311                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor())
312                 .setRequestFinishedListener(requestFinishedListener)
313                 .build()
314                 .start();
315         callback.blockForDone();
316         // We expect that the exception from the listener will not crash the test.
317         requestFinishedListener.blockUntilDone();
318     }
319 
320     @Test
321     @SmallTest
testRequestFinishedListenerThrowInEngineListener()322     public void testRequestFinishedListenerThrowInEngineListener() throws Exception {
323         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
324         requestFinishedListener.makeListenerThrow();
325         mTestRule
326                 .getTestFramework()
327                 .getEngine()
328                 .addRequestFinishedListener(requestFinishedListener);
329         TestUrlRequestCallback callback = new TestUrlRequestCallback();
330         mTestRule
331                 .getTestFramework()
332                 .getEngine()
333                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor())
334                 .build()
335                 .start();
336         callback.blockForDone();
337         // We expect that the exception from the listener will not crash the test.
338         requestFinishedListener.blockUntilDone();
339     }
340 
341     @Test
342     @SmallTest
343     @SuppressWarnings("deprecation")
testRequestFinishedListenerRemoved()344     public void testRequestFinishedListenerRemoved() throws Exception {
345         TestExecutor testExecutor = new TestExecutor();
346         TestRequestFinishedListener requestFinishedListener =
347                 new TestRequestFinishedListener(testExecutor);
348         mTestRule
349                 .getTestFramework()
350                 .getEngine()
351                 .addRequestFinishedListener(requestFinishedListener);
352         TestUrlRequestCallback callback = new TestUrlRequestCallback();
353         UrlRequest.Builder urlRequestBuilder =
354                 mTestRule
355                         .getTestFramework()
356                         .getEngine()
357                         .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
358         UrlRequest request = urlRequestBuilder.build();
359         mTestRule
360                 .getTestFramework()
361                 .getEngine()
362                 .removeRequestFinishedListener(requestFinishedListener);
363         request.start();
364         callback.blockForDone();
365         testExecutor.runAllTasks();
366 
367         assertWithMessage("RequestFinishedInfo.Listener must not be called")
368                 .that(requestFinishedListener.getRequestInfo())
369                 .isNull();
370     }
371 
372     @Test
373     @SmallTest
testRequestFinishedListenerCanceledRequest()374     public void testRequestFinishedListenerCanceledRequest() throws Exception {
375         TestRequestFinishedListener requestFinishedListener = new TestRequestFinishedListener();
376         mTestRule
377                 .getTestFramework()
378                 .getEngine()
379                 .addRequestFinishedListener(requestFinishedListener);
380         TestUrlRequestCallback callback =
381                 new TestUrlRequestCallback() {
382                     @Override
383                     public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
384                         super.onResponseStarted(request, info);
385                         request.cancel();
386                     }
387                 };
388         ExperimentalUrlRequest.Builder urlRequestBuilder =
389                 mTestRule
390                         .getTestFramework()
391                         .getEngine()
392                         .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
393         Date startTime = new Date();
394         urlRequestBuilder
395                 .addRequestAnnotation("request annotation")
396                 .addRequestAnnotation(this)
397                 .build()
398                 .start();
399         callback.blockForDone();
400         requestFinishedListener.blockUntilDone();
401         Date endTime = new Date();
402 
403         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
404         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
405         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.CANCELED);
406         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
407 
408         assertThat(requestInfo.getAnnotations()).containsExactly("request annotation", this);
409     }
410 
411     private static class RejectAllTasksExecutor implements Executor {
412         @Override
execute(Runnable task)413         public void execute(Runnable task) {
414             throw new RejectedExecutionException();
415         }
416     }
417 
418     // Checks that CronetURLRequestAdapter::DestroyOnNetworkThread() doesn't crash when metrics
419     // collection is enabled and the URLRequest hasn't been created. See http://crbug.com/675629.
420     @Test
421     @SmallTest
testExceptionInRequestStart()422     public void testExceptionInRequestStart() throws Exception {
423         // The listener in this test shouldn't get any tasks.
424         Executor executor = new RejectAllTasksExecutor();
425         TestRequestFinishedListener requestFinishedListener =
426                 new TestRequestFinishedListener(executor);
427         mTestRule
428                 .getTestFramework()
429                 .getEngine()
430                 .addRequestFinishedListener(requestFinishedListener);
431         TestUrlRequestCallback callback = new TestUrlRequestCallback();
432         ExperimentalUrlRequest.Builder urlRequestBuilder =
433                 mTestRule
434                         .getTestFramework()
435                         .getEngine()
436                         .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
437         // Empty headers are invalid and will cause start() to throw an exception.
438         UrlRequest request = urlRequestBuilder.addHeader("", "").build();
439         IllegalArgumentException e = assertThrows(IllegalArgumentException.class, request::start);
440         assertThat(e).hasMessageThat().isEqualTo("Invalid header with headername: ");
441     }
442 
443     @Test
444     @SmallTest
testMetricsGetters()445     public void testMetricsGetters() throws Exception {
446         long requestStart = 1;
447         long dnsStart = 2;
448         long dnsEnd = -1;
449         long connectStart = 4;
450         long connectEnd = 5;
451         long sslStart = 6;
452         long sslEnd = 7;
453         long sendingStart = 8;
454         long sendingEnd = 9;
455         long pushStart = 10;
456         long pushEnd = 11;
457         long responseStart = 12;
458         long requestEnd = 13;
459         boolean socketReused = true;
460         long sentByteCount = 14;
461         long receivedByteCount = 15;
462         // Make sure nothing gets reordered inside the Metrics class
463         RequestFinishedInfo.Metrics metrics =
464                 new CronetMetrics(
465                         requestStart,
466                         dnsStart,
467                         dnsEnd,
468                         connectStart,
469                         connectEnd,
470                         sslStart,
471                         sslEnd,
472                         sendingStart,
473                         sendingEnd,
474                         pushStart,
475                         pushEnd,
476                         responseStart,
477                         requestEnd,
478                         socketReused,
479                         sentByteCount,
480                         receivedByteCount);
481         assertThat(metrics.getRequestStart()).isEqualTo(new Date(requestStart));
482         // -1 timestamp should translate to null
483         assertThat(metrics.getDnsEnd()).isNull();
484         assertThat(metrics.getDnsStart()).isEqualTo(new Date(dnsStart));
485         assertThat(metrics.getConnectStart()).isEqualTo(new Date(connectStart));
486         assertThat(metrics.getConnectEnd()).isEqualTo(new Date(connectEnd));
487         assertThat(metrics.getSslStart()).isEqualTo(new Date(sslStart));
488         assertThat(metrics.getSslEnd()).isEqualTo(new Date(sslEnd));
489         assertThat(metrics.getPushStart()).isEqualTo(new Date(pushStart));
490         assertThat(metrics.getPushEnd()).isEqualTo(new Date(pushEnd));
491         assertThat(metrics.getResponseStart()).isEqualTo(new Date(responseStart));
492         assertThat(metrics.getRequestEnd()).isEqualTo(new Date(requestEnd));
493         assertThat(metrics.getSocketReused()).isEqualTo(socketReused);
494         assertThat((long) metrics.getSentByteCount()).isEqualTo(sentByteCount);
495         assertThat((long) metrics.getReceivedByteCount()).isEqualTo(receivedByteCount);
496     }
497 
498     @Test
499     @SmallTest
500     @SuppressWarnings("deprecation")
testOrderSuccessfulRequest()501     public void testOrderSuccessfulRequest() throws Exception {
502         final TestUrlRequestCallback callback = new TestUrlRequestCallback();
503         TestRequestFinishedListener requestFinishedListener =
504                 new AssertCallbackDoneRequestFinishedListener(callback);
505         mTestRule
506                 .getTestFramework()
507                 .getEngine()
508                 .addRequestFinishedListener(requestFinishedListener);
509         ExperimentalUrlRequest.Builder urlRequestBuilder =
510                 (ExperimentalUrlRequest.Builder)
511                         mTestRule
512                                 .getTestFramework()
513                                 .getEngine()
514                                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
515         Date startTime = new Date();
516         urlRequestBuilder
517                 .addRequestAnnotation("request annotation")
518                 .addRequestAnnotation(this)
519                 .build()
520                 .start();
521         callback.blockForDone();
522         requestFinishedListener.blockUntilDone();
523         Date endTime = new Date();
524 
525         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
526         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
527         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
528         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
529         assertThat(requestInfo.getAnnotations()).containsExactly("request annotation", this);
530     }
531 
532     @Test
533     @SmallTest
534     @RequiresMinApi(11)
testUpdateAnnotationOnSucceeded()535     public void testUpdateAnnotationOnSucceeded() throws Exception {
536         // The annotation that is updated in onSucceeded() callback.
537         AtomicBoolean requestAnnotation = new AtomicBoolean(false);
538         final TestUrlRequestCallback callback =
539                 new TestUrlRequestCallback() {
540                     @Override
541                     public void onSucceeded(UrlRequest request, UrlResponseInfo info) {
542                         // Add processing information to request annotation.
543                         requestAnnotation.set(true);
544                         super.onSucceeded(request, info);
545                     }
546                 };
547         TestRequestFinishedListener requestFinishedListener =
548                 new AssertCallbackDoneRequestFinishedListener(callback);
549         ExperimentalUrlRequest.Builder urlRequestBuilder =
550                 (ExperimentalUrlRequest.Builder)
551                         mTestRule
552                                 .getTestFramework()
553                                 .getEngine()
554                                 .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
555         Date startTime = new Date();
556         urlRequestBuilder
557                 .addRequestAnnotation(requestAnnotation)
558                 .setRequestFinishedListener(requestFinishedListener)
559                 .build()
560                 .start();
561         callback.blockForDone();
562         requestFinishedListener.blockUntilDone();
563         Date endTime = new Date();
564         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
565         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
566         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.SUCCEEDED);
567         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
568         // Check that annotation got updated in onSucceeded() callback.
569         assertThat(requestInfo.getAnnotations()).containsExactly(requestAnnotation);
570         assertThat(requestAnnotation.get()).isTrue();
571     }
572 
573     @Test
574     @SmallTest
575     // Tests a failed request where the error originates from Java.
testOrderFailedRequestJava()576     public void testOrderFailedRequestJava() throws Exception {
577         final TestUrlRequestCallback callback =
578                 new TestUrlRequestCallback() {
579                     @Override
580                     public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
581                         throw new RuntimeException("make this request fail");
582                     }
583                 };
584         TestRequestFinishedListener requestFinishedListener =
585                 new AssertCallbackDoneRequestFinishedListener(callback);
586         mTestRule
587                 .getTestFramework()
588                 .getEngine()
589                 .addRequestFinishedListener(requestFinishedListener);
590         UrlRequest.Builder urlRequestBuilder =
591                 mTestRule
592                         .getTestFramework()
593                         .getEngine()
594                         .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
595         urlRequestBuilder.build().start();
596         callback.blockForDone();
597         assertThat(callback.mOnErrorCalled).isTrue();
598         requestFinishedListener.blockUntilDone();
599         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
600         assertWithMessage("RequestFinishedInfo.Listener must be called")
601                 .that(requestInfo)
602                 .isNotNull();
603         assertThat(requestInfo.getUrl()).isEqualTo(mUrl);
604         assertThat(requestInfo.getAnnotations()).isEmpty();
605         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.FAILED);
606         assertThat(requestInfo.getException())
607                 .hasMessageThat()
608                 .isEqualTo("Exception received from UrlRequest.Callback");
609         RequestFinishedInfo.Metrics metrics = requestInfo.getMetrics();
610         assertWithMessage("RequestFinishedInfo.getMetrics() must not be null")
611                 .that(metrics)
612                 .isNotNull();
613     }
614 
615     @Test
616     @SmallTest
617     // Tests a failed request where the error originates from native code.
testOrderFailedRequestNative()618     public void testOrderFailedRequestNative() throws Exception {
619         String connectionRefusedUrl = "http://127.0.0.1:3";
620         final TestUrlRequestCallback callback = new TestUrlRequestCallback();
621         TestRequestFinishedListener requestFinishedListener =
622                 new AssertCallbackDoneRequestFinishedListener(callback);
623         mTestRule
624                 .getTestFramework()
625                 .getEngine()
626                 .addRequestFinishedListener(requestFinishedListener);
627         UrlRequest.Builder urlRequestBuilder =
628                 mTestRule
629                         .getTestFramework()
630                         .getEngine()
631                         .newUrlRequestBuilder(
632                                 connectionRefusedUrl, callback, callback.getExecutor());
633         urlRequestBuilder.build().start();
634         callback.blockForDone();
635         assertThat(callback.mOnErrorCalled).isTrue();
636         requestFinishedListener.blockUntilDone();
637         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
638         assertWithMessage("RequestFinishedInfo.Listener must be called")
639                 .that(requestInfo)
640                 .isNotNull();
641         assertThat(requestInfo.getUrl()).isEqualTo(connectionRefusedUrl);
642         assertThat(requestInfo.getAnnotations()).isEmpty();
643         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.FAILED);
644         assertThat(requestInfo.getException()).isNotNull();
645         assertThat(((NetworkException) requestInfo.getException()).getErrorCode())
646                 .isEqualTo(NetworkException.ERROR_CONNECTION_REFUSED);
647         RequestFinishedInfo.Metrics metrics = requestInfo.getMetrics();
648         assertWithMessage("RequestFinishedInfo.getMetrics() must not be null")
649                 .that(metrics)
650                 .isNotNull();
651     }
652 
653     @Test
654     @SmallTest
testOrderCanceledRequest()655     public void testOrderCanceledRequest() throws Exception {
656         final TestUrlRequestCallback callback =
657                 new TestUrlRequestCallback() {
658                     @Override
659                     public void onResponseStarted(UrlRequest request, UrlResponseInfo info) {
660                         super.onResponseStarted(request, info);
661                         request.cancel();
662                     }
663                 };
664 
665         TestRequestFinishedListener requestFinishedListener =
666                 new AssertCallbackDoneRequestFinishedListener(callback);
667         mTestRule
668                 .getTestFramework()
669                 .getEngine()
670                 .addRequestFinishedListener(requestFinishedListener);
671         ExperimentalUrlRequest.Builder urlRequestBuilder =
672                 mTestRule
673                         .getTestFramework()
674                         .getEngine()
675                         .newUrlRequestBuilder(mUrl, callback, callback.getExecutor());
676         Date startTime = new Date();
677         urlRequestBuilder
678                 .addRequestAnnotation("request annotation")
679                 .addRequestAnnotation(this)
680                 .build()
681                 .start();
682         callback.blockForDone();
683         requestFinishedListener.blockUntilDone();
684         Date endTime = new Date();
685 
686         RequestFinishedInfo requestInfo = requestFinishedListener.getRequestInfo();
687         MetricsTestUtil.checkRequestFinishedInfo(requestInfo, mUrl, startTime, endTime);
688         assertThat(requestInfo.getFinishedReason()).isEqualTo(RequestFinishedInfo.CANCELED);
689         MetricsTestUtil.checkHasConnectTiming(requestInfo.getMetrics(), startTime, endTime, false);
690 
691         assertThat(requestInfo.getAnnotations()).containsExactly("request annotation", this);
692     }
693 }
694