• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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 
9 import static org.junit.Assert.assertThrows;
10 
11 import static org.chromium.net.truth.UrlResponseInfoSubject.assertThat;
12 
13 import android.os.ConditionVariable;
14 
15 import androidx.test.ext.junit.runners.AndroidJUnit4;
16 import androidx.test.filters.SmallTest;
17 
18 import com.google.common.collect.Range;
19 
20 import org.junit.After;
21 import org.junit.Before;
22 import org.junit.Rule;
23 import org.junit.Test;
24 import org.junit.rules.ExpectedException;
25 import org.junit.runner.RunWith;
26 
27 import org.chromium.base.test.util.DoNotBatch;
28 import org.chromium.net.CronetTestRule.CronetImplementation;
29 import org.chromium.net.CronetTestRule.IgnoreFor;
30 import org.chromium.net.TestUrlRequestCallback.ResponseStep;
31 import org.chromium.net.UrlRequest.Status;
32 import org.chromium.net.UrlRequest.StatusListener;
33 import org.chromium.net.impl.LoadState;
34 import org.chromium.net.impl.UrlRequestBase;
35 
36 import java.io.IOException;
37 import java.util.concurrent.Executor;
38 import java.util.concurrent.Executors;
39 
40 /**
41  * Tests that {@link org.chromium.net.impl.CronetUrlRequest#getStatus(StatusListener)} works as
42  * expected.
43  */
44 @DoNotBatch(reason = "crbug/1459563")
45 @RunWith(AndroidJUnit4.class)
46 public class GetStatusTest {
47     @Rule public final CronetTestRule mTestRule = CronetTestRule.withAutomaticEngineStartup();
48     @Rule public ExpectedException thrown = ExpectedException.none();
49 
50     @Before
setUp()51     public void setUp() throws Exception {
52         assertThat(
53                         NativeTestServer.startNativeTestServer(
54                                 mTestRule.getTestFramework().getContext()))
55                 .isTrue();
56     }
57 
58     @After
tearDown()59     public void tearDown() throws Exception {
60         NativeTestServer.shutdownNativeTestServer();
61     }
62 
63     @Test
64     @SmallTest
testSimpleGet()65     public void testSimpleGet() throws Exception {
66         String url = NativeTestServer.getEchoMethodURL();
67         TestUrlRequestCallback callback = new TestUrlRequestCallback();
68         callback.setAutoAdvance(false);
69         UrlRequest.Builder builder =
70                 mTestRule
71                         .getTestFramework()
72                         .getEngine()
73                         .newUrlRequestBuilder(url, callback, callback.getExecutor());
74         UrlRequest urlRequest = builder.build();
75         // Calling before request is started should give Status.INVALID,
76         // since the native adapter is not created.
77         TestStatusListener statusListener0 = new TestStatusListener();
78         urlRequest.getStatus(statusListener0);
79         statusListener0.waitUntilOnStatusCalled();
80         assertThat(statusListener0.mOnStatusCalled).isTrue();
81         assertThat(statusListener0.mStatus).isEqualTo(Status.INVALID);
82 
83         urlRequest.start();
84 
85         // Should receive a valid status.
86         TestStatusListener statusListener1 = new TestStatusListener();
87         urlRequest.getStatus(statusListener1);
88         statusListener1.waitUntilOnStatusCalled();
89         assertThat(statusListener1.mOnStatusCalled).isTrue();
90         assertThat(statusListener1.mStatus)
91                 .isIn(Range.closed(Status.IDLE, Status.READING_RESPONSE));
92         callback.waitForNextStep();
93         assertThat(callback.mResponseStep).isEqualTo(ResponseStep.ON_RESPONSE_STARTED);
94         callback.startNextRead(urlRequest);
95 
96         // Should receive a valid status.
97         TestStatusListener statusListener2 = new TestStatusListener();
98         urlRequest.getStatus(statusListener2);
99         statusListener2.waitUntilOnStatusCalled();
100         assertThat(statusListener2.mOnStatusCalled).isTrue();
101         assertThat(statusListener1.mStatus)
102                 .isIn(Range.closed(Status.IDLE, Status.READING_RESPONSE));
103 
104         callback.waitForNextStep();
105         assertThat(callback.mResponseStep).isEqualTo(ResponseStep.ON_READ_COMPLETED);
106 
107         callback.startNextRead(urlRequest);
108         callback.blockForDone();
109 
110         // Calling after request done should give Status.INVALID, since
111         // the native adapter is destroyed.
112         TestStatusListener statusListener3 = new TestStatusListener();
113         urlRequest.getStatus(statusListener3);
114         statusListener3.waitUntilOnStatusCalled();
115         assertThat(statusListener3.mOnStatusCalled).isTrue();
116         assertThat(statusListener3.mStatus).isEqualTo(Status.INVALID);
117 
118         assertThat(callback.getResponseInfoWithChecks()).hasHttpStatusCodeThat().isEqualTo(200);
119         assertThat(callback.mResponseAsString).isEqualTo("GET");
120     }
121 
122     @Test
123     @SmallTest
testInvalidLoadState()124     public void testInvalidLoadState() throws Exception {
125         assertThrows(
126                 IllegalArgumentException.class,
127                 () -> UrlRequestBase.convertLoadState(LoadState.OBSOLETE_WAITING_FOR_APPCACHE));
128         // Expected throw because LoadState.WAITING_FOR_APPCACHE is not mapped.
129 
130         thrown.expect(Throwable.class);
131         UrlRequestBase.convertLoadState(-1);
132         UrlRequestBase.convertLoadState(16);
133     }
134 
135     @Test
136     @SmallTest
137     @IgnoreFor(
138             implementations = {CronetImplementation.FALLBACK},
139             reason = "Relies on timings which are not respected by the fallback implementation")
140     // Regression test for crbug.com/606872.
testGetStatusForUpload()141     public void testGetStatusForUpload() throws Exception {
142         TestUrlRequestCallback callback = new TestUrlRequestCallback();
143         UrlRequest.Builder builder =
144                 mTestRule
145                         .getTestFramework()
146                         .getEngine()
147                         .newUrlRequestBuilder(
148                                 NativeTestServer.getEchoBodyURL(),
149                                 callback,
150                                 callback.getExecutor());
151 
152         final ConditionVariable block = new ConditionVariable();
153         // Use a separate executor for UploadDataProvider so the upload can be
154         // stalled while getStatus gets processed.
155         Executor uploadProviderExecutor = Executors.newSingleThreadExecutor();
156         TestUploadDataProvider dataProvider =
157                 new TestUploadDataProvider(
158                         TestUploadDataProvider.SuccessCallbackMode.SYNC, uploadProviderExecutor) {
159                     @Override
160                     public long getLength() throws IOException {
161                         // Pause the data provider.
162                         block.block();
163                         block.close();
164                         return super.getLength();
165                     }
166                 };
167         dataProvider.addRead("test".getBytes());
168         builder.setUploadDataProvider(dataProvider, uploadProviderExecutor);
169         builder.addHeader("Content-Type", "useless/string");
170         UrlRequest urlRequest = builder.build();
171         TestStatusListener statusListener = new TestStatusListener();
172         urlRequest.start();
173         // Call getStatus() immediately after start(), which will post
174         // startInternal() to the upload provider's executor because there is an
175         // upload. When CronetUrlRequestAdapter::GetStatusOnNetworkThread is
176         // executed, the |url_request_| is null.
177         urlRequest.getStatus(statusListener);
178         statusListener.waitUntilOnStatusCalled();
179         assertThat(statusListener.mOnStatusCalled).isTrue();
180         // The request should be in IDLE state because GetStatusOnNetworkThread
181         // is called before |url_request_| is initialized and started.
182         assertThat(statusListener.mStatus).isEqualTo(Status.IDLE);
183         // Resume the UploadDataProvider.
184         block.open();
185 
186         // Make sure the request is successful and there is no crash.
187         callback.blockForDone();
188         dataProvider.assertClosed();
189 
190         assertThat(dataProvider.getUploadedLength()).isEqualTo(4);
191         assertThat(dataProvider.getNumReadCalls()).isEqualTo(1);
192         assertThat(dataProvider.getNumRewindCalls()).isEqualTo(0);
193 
194         assertThat(callback.getResponseInfoWithChecks()).hasHttpStatusCodeThat().isEqualTo(200);
195         assertThat(callback.mResponseAsString).isEqualTo("test");
196     }
197 
198     private static class TestStatusListener extends StatusListener {
199         boolean mOnStatusCalled;
200         int mStatus = Integer.MAX_VALUE;
201         private final ConditionVariable mBlock = new ConditionVariable();
202 
203         @Override
onStatus(int status)204         public void onStatus(int status) {
205             mOnStatusCalled = true;
206             mStatus = status;
207             mBlock.open();
208         }
209 
waitUntilOnStatusCalled()210         public void waitUntilOnStatusCalled() {
211             mBlock.block();
212             mBlock.close();
213         }
214     }
215 }
216