Allow overlapping sync and async startup requests
[chromium-blink-merge.git] / content / public / android / javatests / src / org / chromium / content / browser / BrowserStartupControllerTest.java
blobd60b04d335c6de3e395110464db9602b481ef8b4
1 // Copyright 2013 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.
5 package org.chromium.content.browser;
7 import android.content.Context;
8 import android.test.InstrumentationTestCase;
9 import android.test.suitebuilder.annotation.SmallTest;
11 import org.chromium.base.ThreadUtils;
12 import org.chromium.base.test.util.AdvancedMockContext;
13 import org.chromium.content.common.ProcessInitException;
14 import org.chromium.content.common.ResultCodes;
16 public class BrowserStartupControllerTest extends InstrumentationTestCase {
18 private TestBrowserStartupController mController;
20 private static class TestBrowserStartupController extends BrowserStartupController {
22 private int mStartupResult;
23 private boolean mLibraryLoadSucceeds;
24 private int mInitializedCounter = 0;
26 @Override
27 void prepareToStartBrowserProcess(int numRenderers) throws ProcessInitException {
28 if (!mLibraryLoadSucceeds) {
29 throw new ProcessInitException(ResultCodes.RESULT_CODE_NATIVE_LIBRARY_LOAD_FAILED);
33 private TestBrowserStartupController(Context context) {
34 super(context);
37 @Override
38 int contentStart() {
39 mInitializedCounter++;
40 if(BrowserStartupController.browserMayStartAsynchonously()) {
41 // Post to the UI thread to emulate what would happen in a real scenario.
42 ThreadUtils.postOnUiThread(new Runnable() {
43 @Override
44 public void run() {
45 BrowserStartupController.browserStartupComplete(mStartupResult);
47 });
48 } else {
49 BrowserStartupController.browserStartupComplete(mStartupResult);
51 return mStartupResult;
54 private int initializedCounter() {
55 return mInitializedCounter;
59 private static class TestStartupCallback implements BrowserStartupController.StartupCallback {
60 private boolean mWasSuccess;
61 private boolean mWasFailure;
62 private boolean mHasStartupResult;
63 private boolean mAlreadyStarted;
65 @Override
66 public void onSuccess(boolean alreadyStarted) {
67 assert !mHasStartupResult;
68 mWasSuccess = true;
69 mAlreadyStarted = alreadyStarted;
70 mHasStartupResult = true;
73 @Override
74 public void onFailure() {
75 assert !mHasStartupResult;
76 mWasFailure = true;
77 mHasStartupResult = true;
81 @Override
82 protected void setUp() throws Exception {
83 super.setUp();
84 Context context = new AdvancedMockContext(getInstrumentation().getTargetContext());
85 mController = new TestBrowserStartupController(context);
86 // Setting the static singleton instance field enables more correct testing, since it is
87 // is possible to call {@link BrowserStartupController#browserStartupComplete(int)} instead
88 // of {@link BrowserStartupController#executeEnqueuedCallbacks(int, boolean)} directly.
89 BrowserStartupController.overrideInstanceForTest(mController);
92 @SmallTest
93 public void testSingleAsynchronousStartupRequest() {
94 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
95 mController.mLibraryLoadSucceeds = true;
96 final TestStartupCallback callback = new TestStartupCallback();
98 // Kick off the asynchronous startup request.
99 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
100 @Override
101 public void run() {
102 mController.startBrowserProcessesAsync(callback);
106 assertTrue("Asynchronous mode should have been set.",
107 BrowserStartupController.browserMayStartAsynchonously());
108 assertEquals("The browser process should have been initialized one time.",
109 1, mController.initializedCounter());
111 // Wait for callbacks to complete.
112 getInstrumentation().waitForIdleSync();
114 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
115 assertTrue("Callback should have been a success.", callback.mWasSuccess);
116 assertFalse("Callback should be told that the browser process was not already started.",
117 callback.mAlreadyStarted);
120 @SmallTest
121 public void testMultipleAsynchronousStartupRequests() {
122 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
123 mController.mLibraryLoadSucceeds = true;
124 final TestStartupCallback callback1 = new TestStartupCallback();
125 final TestStartupCallback callback2 = new TestStartupCallback();
126 final TestStartupCallback callback3 = new TestStartupCallback();
128 // Kick off the asynchronous startup requests.
129 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
130 @Override
131 public void run() {
132 mController.startBrowserProcessesAsync(callback1);
135 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
136 @Override
137 public void run() {
138 mController.startBrowserProcessesAsync(callback2);
141 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
142 @Override
143 public void run() {
144 mController.addStartupCompletedObserver(callback3);
148 assertTrue("Asynchronous mode should have been set.",
149 BrowserStartupController.browserMayStartAsynchonously());
150 assertEquals("The browser process should have been initialized one time.",
151 1, mController.initializedCounter());
153 // Wait for callbacks to complete.
154 getInstrumentation().waitForIdleSync();
156 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
157 assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
158 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
159 assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
160 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
161 assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
162 // Some startup tasks might have been enqueued after the browser process was started, but
163 // not the first one which kicked of the startup.
164 assertFalse("Callback 1 should be told that the browser process was not already started.",
165 callback1.mAlreadyStarted);
168 @SmallTest
169 public void testConsecutiveAsynchronousStartupRequests() {
170 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
171 mController.mLibraryLoadSucceeds = true;
172 final TestStartupCallback callback1 = new TestStartupCallback();
173 final TestStartupCallback callback2 = new TestStartupCallback();
175 // Kick off the asynchronous startup requests.
176 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
177 @Override
178 public void run() {
179 mController.startBrowserProcessesAsync(callback1);
182 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
183 @Override
184 public void run() {
185 mController.addStartupCompletedObserver(callback2);
189 assertTrue("Asynchronous mode should have been set.",
190 BrowserStartupController.browserMayStartAsynchonously());
191 assertEquals("The browser process should have been initialized one time.",
192 1, mController.initializedCounter());
194 // Wait for callbacks to complete.
195 getInstrumentation().waitForIdleSync();
197 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
198 assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
199 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
200 assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
202 final TestStartupCallback callback3 = new TestStartupCallback();
203 final TestStartupCallback callback4 = new TestStartupCallback();
205 // Kick off more asynchronous startup requests.
206 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
207 @Override
208 public void run() {
209 mController.startBrowserProcessesAsync(callback3);
212 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
213 @Override
214 public void run() {
215 mController.addStartupCompletedObserver(callback4);
219 // Wait for callbacks to complete.
220 getInstrumentation().waitForIdleSync();
222 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
223 assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
224 assertTrue("Callback 3 should be told that the browser process was already started.",
225 callback3.mAlreadyStarted);
226 assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
227 assertTrue("Callback 4 should have been a success.", callback4.mWasSuccess);
228 assertTrue("Callback 4 should be told that the browser process was already started.",
229 callback4.mAlreadyStarted);
232 @SmallTest
233 public void testSingleFailedAsynchronousStartupRequest() {
234 mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
235 mController.mLibraryLoadSucceeds = true;
236 final TestStartupCallback callback = new TestStartupCallback();
238 // Kick off the asynchronous startup request.
239 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
240 @Override
241 public void run() {
242 mController.startBrowserProcessesAsync(callback);
246 assertTrue("Asynchronous mode should have been set.",
247 BrowserStartupController.browserMayStartAsynchonously());
248 assertEquals("The browser process should have been initialized one time.",
249 1, mController.initializedCounter());
251 // Wait for callbacks to complete.
252 getInstrumentation().waitForIdleSync();
254 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
255 assertTrue("Callback should have been a failure.", callback.mWasFailure);
258 @SmallTest
259 public void testConsecutiveFailedAsynchronousStartupRequests() {
260 mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
261 mController.mLibraryLoadSucceeds = true;
262 final TestStartupCallback callback1 = new TestStartupCallback();
263 final TestStartupCallback callback2 = new TestStartupCallback();
265 // Kick off the asynchronous startup requests.
266 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
267 @Override
268 public void run() {
269 mController.startBrowserProcessesAsync(callback1);
272 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
273 @Override
274 public void run() {
275 mController.addStartupCompletedObserver(callback2);
279 assertTrue("Asynchronous mode should have been set.",
280 BrowserStartupController.browserMayStartAsynchonously());
281 assertEquals("The browser process should have been initialized one time.",
282 1, mController.initializedCounter());
284 // Wait for callbacks to complete.
285 getInstrumentation().waitForIdleSync();
287 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
288 assertTrue("Callback 1 should have been a failure.", callback1.mWasFailure);
289 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
290 assertTrue("Callback 2 should have been a failure.", callback2.mWasFailure);
292 final TestStartupCallback callback3 = new TestStartupCallback();
293 final TestStartupCallback callback4 = new TestStartupCallback();
295 // Kick off more asynchronous startup requests.
296 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
297 @Override
298 public void run() {
299 mController.startBrowserProcessesAsync(callback3);
302 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
303 @Override
304 public void run() {
305 mController.addStartupCompletedObserver(callback4);
309 // Wait for callbacks to complete.
310 getInstrumentation().waitForIdleSync();
312 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
313 assertTrue("Callback 3 should have been a failure.", callback3.mWasFailure);
314 assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
315 assertTrue("Callback 4 should have been a failure.", callback4.mWasFailure);
318 @SmallTest
319 public void testSingleSynchronousRequest() {
320 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
321 mController.mLibraryLoadSucceeds = true;
322 // Kick off the synchronous startup.
323 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
324 @Override
325 public void run() {
326 assertTrue("Browser should have started successfully",
327 mController.startBrowserProcessesSync(1));
330 assertFalse("Synchronous mode should have been set",
331 BrowserStartupController.browserMayStartAsynchonously());
333 assertEquals("The browser process should have been initialized one time.",
334 1, mController.initializedCounter());
337 @SmallTest
338 public void testAsyncThenSyncRequests() {
339 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
340 mController.mLibraryLoadSucceeds = true;
341 final TestStartupCallback callback = new TestStartupCallback();
343 // Kick off the startups.
344 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
345 @Override
346 public void run() {
347 mController.startBrowserProcessesAsync(callback);
348 // To ensure that the async startup doesn't complete too soon we have
349 // to do both these in a since Runnable instance. This avoids the
350 // unpredictable race that happens in real situations.
351 assertTrue("Browser should have started successfully",
352 mController.startBrowserProcessesSync(1));
355 assertFalse("Synchronous mode should have been set",
356 BrowserStartupController.browserMayStartAsynchonously());
358 assertEquals("The browser process should have been initialized twice.",
359 2, mController.initializedCounter());
361 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
362 assertTrue("Callback should have been a success.", callback.mWasSuccess);
363 assertFalse("Callback should be told that the browser process was not already started.",
364 callback.mAlreadyStarted);
367 @SmallTest
368 public void testSyncThenAsyncRequests() {
369 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
370 mController.mLibraryLoadSucceeds = true;
371 final TestStartupCallback callback = new TestStartupCallback();
373 // Do a synchronous startup first.
374 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
375 @Override
376 public void run() {
377 assertTrue("Browser should have started successfully",
378 mController.startBrowserProcessesSync(1));
382 assertEquals("The browser process should have been initialized once.",
383 1, mController.initializedCounter());
385 assertFalse("Synchronous mode should have been set",
386 BrowserStartupController.browserMayStartAsynchonously());
388 // Kick off the asynchronous startup request. This should just queue the callback.
389 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
390 @Override
391 public void run() {
392 mController.startBrowserProcessesAsync(callback);
396 assertEquals("The browser process should not have been initialized a second time.",
397 1, mController.initializedCounter());
399 // Wait for callbacks to complete.
400 getInstrumentation().waitForIdleSync();
402 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
403 assertTrue("Callback should have been a success.", callback.mWasSuccess);
404 assertTrue("Callback should be told that the browser process was already started.",
405 callback.mAlreadyStarted);
408 @SmallTest
409 public void testLibraryLoadFails() {
410 mController.mLibraryLoadSucceeds = false;
411 final TestStartupCallback callback = new TestStartupCallback();
413 // Kick off the asynchronous startup request.
414 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
415 @Override
416 public void run() {
417 mController.startBrowserProcessesAsync(callback);
421 assertEquals("The browser process should not have been initialized.",
422 0, mController.initializedCounter());
424 // Wait for callbacks to complete.
425 getInstrumentation().waitForIdleSync();
427 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
428 assertFalse("Callback should have been a failure.", callback.mWasSuccess);
429 assertFalse("Callback should be told that the browser process was not already started.",
430 callback.mAlreadyStarted);