• 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 org.junit.Assert.assertEquals;
8 import static org.junit.Assert.assertFalse;
9 import static org.junit.Assert.assertTrue;
10 
11 import static org.chromium.net.CronetTestRule.getContext;
12 
13 import android.net.http.UrlRequest;
14 
15 import androidx.test.ext.junit.runners.AndroidJUnit4;
16 import androidx.test.filters.SmallTest;
17 
18 import org.junit.After;
19 import org.junit.Before;
20 import org.junit.Rule;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 
24 import org.chromium.net.CronetTestRule.CronetTestFramework;
25 import org.chromium.net.CronetTestRule.OnlyRunNativeCronet;
26 import org.chromium.net.impl.CronetUploadDataStream;
27 import org.chromium.net.impl.CronetUrlRequest;
28 
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 
34 /**
35  * Tests that directly drive {@code CronetUploadDataStream} and
36  * {@code UploadDataProvider} to simulate different ordering of reset, init,
37  * read, and rewind calls.
38  */
39 @RunWith(AndroidJUnit4.class)
40 public class CronetUploadTest {
41     @Rule
42     public final CronetTestRule mTestRule = new CronetTestRule();
43 
44     private TestDrivenDataProvider mDataProvider;
45     private CronetUploadDataStream mUploadDataStream;
46     private TestUploadDataStreamHandler mHandler;
47     private CronetTestFramework mTestFramework;
48 
49     @Before
50     @SuppressWarnings({"PrimitiveArrayPassedToVarargsMethod", "ArraysAsListPrimitiveArray"})
setUp()51     public void setUp() throws Exception {
52         mTestFramework = mTestRule.startCronetTestFramework();
53         ExecutorService executor = Executors.newSingleThreadExecutor();
54         List<byte[]> reads = Arrays.asList("hello".getBytes());
55         mDataProvider = new TestDrivenDataProvider(executor, reads);
56 
57         // Creates a dummy CronetUrlRequest, which is not used to drive CronetUploadDataStream.
58         TestUrlRequestCallback callback = new TestUrlRequestCallback();
59         UrlRequest.Builder builder = mTestFramework.mCronetEngine.newUrlRequestBuilder(
60                 "https://dummy.url", callback, callback.getExecutor());
61         UrlRequest urlRequest = builder.build();
62 
63         mUploadDataStream =
64                 new CronetUploadDataStream(mDataProvider, executor, (CronetUrlRequest) urlRequest);
65         mHandler = new TestUploadDataStreamHandler(
66                 getContext(), mUploadDataStream.createUploadDataStreamForTesting());
67     }
68 
69     @After
tearDown()70     public void tearDown() throws Exception {
71         // Destroy handler's native objects.
72         mHandler.destroyNativeObjects();
73     }
74 
75     /**
76      * Tests that after some data is read, init triggers a rewind, and that
77      * before the rewind completes, init blocks.
78      */
79     @Test
80     @SmallTest
81     @OnlyRunNativeCronet
testInitTriggersRewindAndInitBeforeRewindCompletes()82     public void testInitTriggersRewindAndInitBeforeRewindCompletes() throws Exception {
83         // Init completes synchronously and read succeeds.
84         assertTrue(mHandler.init());
85         mHandler.read();
86         mDataProvider.waitForReadRequest();
87         mHandler.checkReadCallbackNotInvoked();
88         mDataProvider.onReadSucceeded(mUploadDataStream);
89         mHandler.waitForReadComplete();
90         mDataProvider.assertReadNotPending();
91         assertEquals(0, mDataProvider.getNumRewindCalls());
92         assertEquals(1, mDataProvider.getNumReadCalls());
93         assertEquals("hello", mHandler.getData());
94 
95         // Reset and then init, which should trigger a rewind.
96         mHandler.reset();
97         assertEquals("", mHandler.getData());
98         assertFalse(mHandler.init());
99         mDataProvider.waitForRewindRequest();
100         mHandler.checkInitCallbackNotInvoked();
101 
102         // Before rewind completes, reset and init should block.
103         mHandler.reset();
104         assertFalse(mHandler.init());
105 
106         // Signal rewind completes, and wait for init to complete.
107         mHandler.checkInitCallbackNotInvoked();
108         mDataProvider.onRewindSucceeded(mUploadDataStream);
109         mHandler.waitForInitComplete();
110         mDataProvider.assertRewindNotPending();
111 
112         // Read should complete successfully since init has completed.
113         mHandler.read();
114         mDataProvider.waitForReadRequest();
115         mHandler.checkReadCallbackNotInvoked();
116         mDataProvider.onReadSucceeded(mUploadDataStream);
117         mHandler.waitForReadComplete();
118         mDataProvider.assertReadNotPending();
119         assertEquals(1, mDataProvider.getNumRewindCalls());
120         assertEquals(2, mDataProvider.getNumReadCalls());
121         assertEquals("hello", mHandler.getData());
122     }
123 
124     /**
125      * Tests that after some data is read, init triggers a rewind, and that
126      * after the rewind completes, init does not block.
127      */
128     @Test
129     @SmallTest
130     @OnlyRunNativeCronet
testInitTriggersRewindAndInitAfterRewindCompletes()131     public void testInitTriggersRewindAndInitAfterRewindCompletes() throws Exception {
132         // Init completes synchronously and read succeeds.
133         assertTrue(mHandler.init());
134         mHandler.read();
135         mDataProvider.waitForReadRequest();
136         mHandler.checkReadCallbackNotInvoked();
137         mDataProvider.onReadSucceeded(mUploadDataStream);
138         mHandler.waitForReadComplete();
139         mDataProvider.assertReadNotPending();
140         assertEquals(0, mDataProvider.getNumRewindCalls());
141         assertEquals(1, mDataProvider.getNumReadCalls());
142         assertEquals("hello", mHandler.getData());
143 
144         // Reset and then init, which should trigger a rewind.
145         mHandler.reset();
146         assertEquals("", mHandler.getData());
147         assertFalse(mHandler.init());
148         mDataProvider.waitForRewindRequest();
149         mHandler.checkInitCallbackNotInvoked();
150 
151         // Signal rewind completes, and wait for init to complete.
152         mDataProvider.onRewindSucceeded(mUploadDataStream);
153         mHandler.waitForInitComplete();
154         mDataProvider.assertRewindNotPending();
155 
156         // Reset and init should not block, since rewind has completed.
157         mHandler.reset();
158         assertTrue(mHandler.init());
159 
160         // Read should complete successfully since init has completed.
161         mHandler.read();
162         mDataProvider.waitForReadRequest();
163         mHandler.checkReadCallbackNotInvoked();
164         mDataProvider.onReadSucceeded(mUploadDataStream);
165         mHandler.waitForReadComplete();
166         mDataProvider.assertReadNotPending();
167         assertEquals(1, mDataProvider.getNumRewindCalls());
168         assertEquals(2, mDataProvider.getNumReadCalls());
169         assertEquals("hello", mHandler.getData());
170     }
171 
172     /**
173      * Tests that if init before read completes, a rewind is triggered when
174      * read completes.
175      */
176     @Test
177     @SmallTest
178     @OnlyRunNativeCronet
testReadCompleteTriggerRewind()179     public void testReadCompleteTriggerRewind() throws Exception {
180         // Reset and init before read completes.
181         assertTrue(mHandler.init());
182         mHandler.read();
183         mDataProvider.waitForReadRequest();
184         mHandler.checkReadCallbackNotInvoked();
185         mHandler.reset();
186         // Init should return asynchronously, since there is a pending read.
187         assertFalse(mHandler.init());
188         mDataProvider.assertRewindNotPending();
189         mHandler.checkInitCallbackNotInvoked();
190         assertEquals(0, mDataProvider.getNumRewindCalls());
191         assertEquals(1, mDataProvider.getNumReadCalls());
192         assertEquals("", mHandler.getData());
193 
194         // Read completes should trigger a rewind.
195         mDataProvider.onReadSucceeded(mUploadDataStream);
196         mDataProvider.waitForRewindRequest();
197         mHandler.checkInitCallbackNotInvoked();
198         mDataProvider.onRewindSucceeded(mUploadDataStream);
199         mHandler.waitForInitComplete();
200         mDataProvider.assertRewindNotPending();
201         assertEquals(1, mDataProvider.getNumRewindCalls());
202         assertEquals(1, mDataProvider.getNumReadCalls());
203         assertEquals("", mHandler.getData());
204     }
205 
206     /**
207      * Tests that when init again after rewind completes, no additional rewind
208      * is triggered. This test is the same as testReadCompleteTriggerRewind
209      * except that this test invokes reset and init again in the end.
210      */
211     @Test
212     @SmallTest
213     @OnlyRunNativeCronet
testReadCompleteTriggerRewindOnlyOneRewind()214     public void testReadCompleteTriggerRewindOnlyOneRewind() throws Exception {
215         testReadCompleteTriggerRewind();
216         // Reset and Init again, no rewind should happen.
217         mHandler.reset();
218         assertTrue(mHandler.init());
219         mDataProvider.assertRewindNotPending();
220         assertEquals(1, mDataProvider.getNumRewindCalls());
221         assertEquals(1, mDataProvider.getNumReadCalls());
222         assertEquals("", mHandler.getData());
223     }
224 
225     /**
226      * Tests that if reset before read completes, no rewind is triggered, and
227      * that a following init triggers rewind.
228      */
229     @Test
230     @SmallTest
231     @OnlyRunNativeCronet
testResetBeforeReadCompleteAndInitTriggerRewind()232     public void testResetBeforeReadCompleteAndInitTriggerRewind() throws Exception {
233         // Reset before read completes. Rewind is not triggered.
234         assertTrue(mHandler.init());
235         mHandler.read();
236         mDataProvider.waitForReadRequest();
237         mHandler.checkReadCallbackNotInvoked();
238         mHandler.reset();
239         mDataProvider.onReadSucceeded(mUploadDataStream);
240         mDataProvider.assertRewindNotPending();
241         assertEquals(0, mDataProvider.getNumRewindCalls());
242         assertEquals(1, mDataProvider.getNumReadCalls());
243         assertEquals("", mHandler.getData());
244 
245         // Init should trigger a rewind.
246         assertFalse(mHandler.init());
247         mDataProvider.waitForRewindRequest();
248         mHandler.checkInitCallbackNotInvoked();
249         mDataProvider.onRewindSucceeded(mUploadDataStream);
250         mHandler.waitForInitComplete();
251         mDataProvider.assertRewindNotPending();
252         assertEquals(1, mDataProvider.getNumRewindCalls());
253         assertEquals(1, mDataProvider.getNumReadCalls());
254         assertEquals("", mHandler.getData());
255     }
256 
257     /**
258      * Tests that there is no crash when native CronetUploadDataStream is
259      * destroyed while read is pending. The test is racy since the read could
260      * complete either before or after the Java CronetUploadDataStream's
261      * onDestroyUploadDataStream() method is invoked. However, the test should
262      * pass either way, though we are interested in the latter case.
263      */
264     @Test
265     @SmallTest
266     @OnlyRunNativeCronet
testDestroyNativeStreamBeforeReadComplete()267     public void testDestroyNativeStreamBeforeReadComplete() throws Exception {
268         // Start a read and wait for it to be pending.
269         assertTrue(mHandler.init());
270         mHandler.read();
271         mDataProvider.waitForReadRequest();
272         mHandler.checkReadCallbackNotInvoked();
273 
274         // Destroy the C++ TestUploadDataStreamHandler. The handler will then
275         // destroy the C++ CronetUploadDataStream it owns on the network thread.
276         // That will result in calling the Java CronetUploadDataSteam's
277         // onUploadDataStreamDestroyed() method on its executor thread, which
278         // will then destroy the CronetUploadDataStreamAdapter.
279         mHandler.destroyNativeObjects();
280 
281         // Make the read complete should not encounter a crash.
282         mDataProvider.onReadSucceeded(mUploadDataStream);
283 
284         assertEquals(0, mDataProvider.getNumRewindCalls());
285         assertEquals(1, mDataProvider.getNumReadCalls());
286     }
287 
288     /**
289      * Tests that there is no crash when native CronetUploadDataStream is
290      * destroyed while rewind is pending. The test is racy since rewind could
291      * complete either before or after the Java CronetUploadDataStream's
292      * onDestroyUploadDataStream() method is invoked. However, the test should
293      * pass either way, though we are interested in the latter case.
294      */
295     @Test
296     @SmallTest
297     @OnlyRunNativeCronet
testDestroyNativeStreamBeforeRewindComplete()298     public void testDestroyNativeStreamBeforeRewindComplete() throws Exception {
299         // Start a read and wait for it to complete.
300         assertTrue(mHandler.init());
301         mHandler.read();
302         mDataProvider.waitForReadRequest();
303         mHandler.checkReadCallbackNotInvoked();
304         mDataProvider.onReadSucceeded(mUploadDataStream);
305         mHandler.waitForReadComplete();
306         mDataProvider.assertReadNotPending();
307         assertEquals(0, mDataProvider.getNumRewindCalls());
308         assertEquals(1, mDataProvider.getNumReadCalls());
309         assertEquals("hello", mHandler.getData());
310 
311         // Reset and then init, which should trigger a rewind.
312         mHandler.reset();
313         assertEquals("", mHandler.getData());
314         assertFalse(mHandler.init());
315         mDataProvider.waitForRewindRequest();
316         mHandler.checkInitCallbackNotInvoked();
317 
318         // Destroy the C++ TestUploadDataStreamHandler. The handler will then
319         // destroy the C++ CronetUploadDataStream it owns on the network thread.
320         // That will result in calling the Java CronetUploadDataSteam's
321         // onUploadDataStreamDestroyed() method on its executor thread, which
322         // will then destroy the CronetUploadDataStreamAdapter.
323         mHandler.destroyNativeObjects();
324 
325         // Signal rewind completes, and wait for init to complete.
326         mDataProvider.onRewindSucceeded(mUploadDataStream);
327 
328         assertEquals(1, mDataProvider.getNumRewindCalls());
329         assertEquals(1, mDataProvider.getNumReadCalls());
330     }
331 }
332