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.library_loader.LoaderErrors;
13 import org.chromium.base.library_loader.ProcessInitException;
14 import org.chromium.base.test.util.AdvancedMockContext;
17 * Test of BrowserStartupController
19 public class BrowserStartupControllerTest extends InstrumentationTestCase {
21 private TestBrowserStartupController mController;
23 private static class TestBrowserStartupController extends BrowserStartupController {
25 private int mStartupResult;
26 private boolean mLibraryLoadSucceeds;
27 private int mInitializedCounter = 0;
30 void prepareToStartBrowserProcess(boolean singleProcess) throws ProcessInitException {
31 if (!mLibraryLoadSucceeds) {
32 throw new ProcessInitException(
33 LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED);
37 private TestBrowserStartupController(Context context) {
43 mInitializedCounter++;
44 if (BrowserStartupController.browserMayStartAsynchonously()) {
45 // Post to the UI thread to emulate what would happen in a real scenario.
46 ThreadUtils.postOnUiThread(new Runnable() {
49 BrowserStartupController.browserStartupComplete(mStartupResult);
53 BrowserStartupController.browserStartupComplete(mStartupResult);
55 return mStartupResult;
58 private int initializedCounter() {
59 return mInitializedCounter;
63 private static class TestStartupCallback implements BrowserStartupController.StartupCallback {
64 private boolean mWasSuccess;
65 private boolean mWasFailure;
66 private boolean mHasStartupResult;
67 private boolean mAlreadyStarted;
70 public void onSuccess(boolean alreadyStarted) {
71 assert !mHasStartupResult;
73 mAlreadyStarted = alreadyStarted;
74 mHasStartupResult = true;
78 public void onFailure() {
79 assert !mHasStartupResult;
81 mHasStartupResult = true;
86 protected void setUp() throws Exception {
88 Context context = new AdvancedMockContext(getInstrumentation().getTargetContext());
89 mController = new TestBrowserStartupController(context);
90 // Setting the static singleton instance field enables more correct testing, since it is
91 // is possible to call {@link BrowserStartupController#browserStartupComplete(int)} instead
92 // of {@link BrowserStartupController#executeEnqueuedCallbacks(int, boolean)} directly.
93 BrowserStartupController.overrideInstanceForTest(mController);
97 public void testSingleAsynchronousStartupRequest() {
98 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
99 mController.mLibraryLoadSucceeds = true;
100 final TestStartupCallback callback = new TestStartupCallback();
102 // Kick off the asynchronous startup request.
103 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
107 mController.startBrowserProcessesAsync(callback);
108 } catch (Exception e) {
109 fail("Browser should have started successfully");
114 assertTrue("Asynchronous mode should have been set.",
115 BrowserStartupController.browserMayStartAsynchonously());
116 assertEquals("The browser process should have been initialized one time.", 1,
117 mController.initializedCounter());
119 // Wait for callbacks to complete.
120 getInstrumentation().waitForIdleSync();
122 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
123 assertTrue("Callback should have been a success.", callback.mWasSuccess);
124 assertFalse("Callback should be told that the browser process was not already started.",
125 callback.mAlreadyStarted);
129 public void testMultipleAsynchronousStartupRequests() {
130 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
131 mController.mLibraryLoadSucceeds = true;
132 final TestStartupCallback callback1 = new TestStartupCallback();
133 final TestStartupCallback callback2 = new TestStartupCallback();
134 final TestStartupCallback callback3 = new TestStartupCallback();
136 // Kick off the asynchronous startup requests.
137 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
141 mController.startBrowserProcessesAsync(callback1);
142 } catch (Exception e) {
143 fail("Browser should have started successfully");
147 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
151 mController.startBrowserProcessesAsync(callback2);
152 } catch (Exception e) {
153 fail("Browser should have started successfully");
157 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
160 mController.addStartupCompletedObserver(callback3);
164 assertTrue("Asynchronous mode should have been set.",
165 BrowserStartupController.browserMayStartAsynchonously());
166 assertEquals("The browser process should have been initialized one time.", 1,
167 mController.initializedCounter());
169 // Wait for callbacks to complete.
170 getInstrumentation().waitForIdleSync();
172 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
173 assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
174 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
175 assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
176 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
177 assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
178 // Some startup tasks might have been enqueued after the browser process was started, but
179 // not the first one which kicked of the startup.
180 assertFalse("Callback 1 should be told that the browser process was not already started.",
181 callback1.mAlreadyStarted);
185 public void testConsecutiveAsynchronousStartupRequests() {
186 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
187 mController.mLibraryLoadSucceeds = true;
188 final TestStartupCallback callback1 = new TestStartupCallback();
189 final TestStartupCallback callback2 = new TestStartupCallback();
191 // Kick off the asynchronous startup requests.
192 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
196 mController.startBrowserProcessesAsync(callback1);
197 } catch (Exception e) {
198 fail("Browser should have started successfully");
202 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
205 mController.addStartupCompletedObserver(callback2);
209 assertTrue("Asynchronous mode should have been set.",
210 BrowserStartupController.browserMayStartAsynchonously());
211 assertEquals("The browser process should have been initialized one time.", 1,
212 mController.initializedCounter());
214 // Wait for callbacks to complete.
215 getInstrumentation().waitForIdleSync();
217 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
218 assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
219 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
220 assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
222 final TestStartupCallback callback3 = new TestStartupCallback();
223 final TestStartupCallback callback4 = new TestStartupCallback();
225 // Kick off more asynchronous startup requests.
226 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
230 mController.startBrowserProcessesAsync(callback3);
231 } catch (Exception e) {
232 fail("Browser should have started successfully");
236 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
239 mController.addStartupCompletedObserver(callback4);
243 // Wait for callbacks to complete.
244 getInstrumentation().waitForIdleSync();
246 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
247 assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
248 assertTrue("Callback 3 should be told that the browser process was already started.",
249 callback3.mAlreadyStarted);
250 assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
251 assertTrue("Callback 4 should have been a success.", callback4.mWasSuccess);
252 assertTrue("Callback 4 should be told that the browser process was already started.",
253 callback4.mAlreadyStarted);
257 public void testSingleFailedAsynchronousStartupRequest() {
258 mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
259 mController.mLibraryLoadSucceeds = true;
260 final TestStartupCallback callback = new TestStartupCallback();
262 // Kick off the asynchronous startup request.
263 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
267 mController.startBrowserProcessesAsync(callback);
268 } catch (Exception e) {
269 fail("Browser should have started successfully");
274 assertTrue("Asynchronous mode should have been set.",
275 BrowserStartupController.browserMayStartAsynchonously());
276 assertEquals("The browser process should have been initialized one time.", 1,
277 mController.initializedCounter());
279 // Wait for callbacks to complete.
280 getInstrumentation().waitForIdleSync();
282 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
283 assertTrue("Callback should have been a failure.", callback.mWasFailure);
287 public void testConsecutiveFailedAsynchronousStartupRequests() {
288 mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
289 mController.mLibraryLoadSucceeds = true;
290 final TestStartupCallback callback1 = new TestStartupCallback();
291 final TestStartupCallback callback2 = new TestStartupCallback();
293 // Kick off the asynchronous startup requests.
294 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
298 mController.startBrowserProcessesAsync(callback1);
299 } catch (Exception e) {
300 fail("Browser should have started successfully");
304 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
307 mController.addStartupCompletedObserver(callback2);
311 assertTrue("Asynchronous mode should have been set.",
312 BrowserStartupController.browserMayStartAsynchonously());
313 assertEquals("The browser process should have been initialized one time.", 1,
314 mController.initializedCounter());
316 // Wait for callbacks to complete.
317 getInstrumentation().waitForIdleSync();
319 assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
320 assertTrue("Callback 1 should have been a failure.", callback1.mWasFailure);
321 assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
322 assertTrue("Callback 2 should have been a failure.", callback2.mWasFailure);
324 final TestStartupCallback callback3 = new TestStartupCallback();
325 final TestStartupCallback callback4 = new TestStartupCallback();
327 // Kick off more asynchronous startup requests.
328 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
332 mController.startBrowserProcessesAsync(callback3);
333 } catch (Exception e) {
334 fail("Browser should have started successfully");
338 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
341 mController.addStartupCompletedObserver(callback4);
345 // Wait for callbacks to complete.
346 getInstrumentation().waitForIdleSync();
348 assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
349 assertTrue("Callback 3 should have been a failure.", callback3.mWasFailure);
350 assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
351 assertTrue("Callback 4 should have been a failure.", callback4.mWasFailure);
355 public void testSingleSynchronousRequest() {
356 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
357 mController.mLibraryLoadSucceeds = true;
358 // Kick off the synchronous startup.
359 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
363 mController.startBrowserProcessesSync(false);
364 } catch (Exception e) {
365 fail("Browser should have started successfully");
369 assertFalse("Synchronous mode should have been set",
370 BrowserStartupController.browserMayStartAsynchonously());
372 assertEquals("The browser process should have been initialized one time.", 1,
373 mController.initializedCounter());
377 public void testAsyncThenSyncRequests() {
378 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
379 mController.mLibraryLoadSucceeds = true;
380 final TestStartupCallback callback = new TestStartupCallback();
382 // Kick off the startups.
383 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
387 mController.startBrowserProcessesAsync(callback);
388 } catch (Exception e) {
389 fail("Browser should have started successfully");
391 // To ensure that the async startup doesn't complete too soon we have
392 // to do both these in a since Runnable instance. This avoids the
393 // unpredictable race that happens in real situations.
395 mController.startBrowserProcessesSync(false);
396 } catch (Exception e) {
397 fail("Browser should have started successfully");
401 assertFalse("Synchronous mode should have been set",
402 BrowserStartupController.browserMayStartAsynchonously());
404 assertEquals("The browser process should have been initialized twice.", 2,
405 mController.initializedCounter());
407 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
408 assertTrue("Callback should have been a success.", callback.mWasSuccess);
409 assertFalse("Callback should be told that the browser process was not already started.",
410 callback.mAlreadyStarted);
414 public void testSyncThenAsyncRequests() {
415 mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
416 mController.mLibraryLoadSucceeds = true;
417 final TestStartupCallback callback = new TestStartupCallback();
419 // Do a synchronous startup first.
420 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
424 mController.startBrowserProcessesSync(false);
425 } catch (Exception e) {
426 fail("Browser should have started successfully");
431 assertEquals("The browser process should have been initialized once.", 1,
432 mController.initializedCounter());
434 assertFalse("Synchronous mode should have been set",
435 BrowserStartupController.browserMayStartAsynchonously());
437 // Kick off the asynchronous startup request. This should just queue the callback.
438 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
442 mController.startBrowserProcessesAsync(callback);
443 } catch (Exception e) {
444 fail("Browser should have started successfully");
449 assertEquals("The browser process should not have been initialized a second time.", 1,
450 mController.initializedCounter());
452 // Wait for callbacks to complete.
453 getInstrumentation().waitForIdleSync();
455 assertTrue("Callback should have been executed.", callback.mHasStartupResult);
456 assertTrue("Callback should have been a success.", callback.mWasSuccess);
457 assertTrue("Callback should be told that the browser process was already started.",
458 callback.mAlreadyStarted);
462 public void testLibraryLoadFails() {
463 mController.mLibraryLoadSucceeds = false;
464 final TestStartupCallback callback = new TestStartupCallback();
466 // Kick off the asynchronous startup request.
467 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
471 mController.startBrowserProcessesAsync(callback);
472 fail("Browser should not have started successfully");
473 } catch (Exception e) {
474 // Exception expected, ignore.
479 assertEquals("The browser process should not have been initialized.", 0,
480 mController.initializedCounter());
482 // Wait for callbacks to complete.
483 getInstrumentation().waitForIdleSync();