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;
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
) {
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() {
45 BrowserStartupController
.browserStartupComplete(mStartupResult
);
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
;
66 public void onSuccess(boolean alreadyStarted
) {
67 assert !mHasStartupResult
;
69 mAlreadyStarted
= alreadyStarted
;
70 mHasStartupResult
= true;
74 public void onFailure() {
75 assert !mHasStartupResult
;
77 mHasStartupResult
= true;
82 protected void setUp() throws Exception
{
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
);
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() {
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
);
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() {
132 mController
.startBrowserProcessesAsync(callback1
);
135 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
138 mController
.startBrowserProcessesAsync(callback2
);
141 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
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
);
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() {
179 mController
.startBrowserProcessesAsync(callback1
);
182 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
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() {
209 mController
.startBrowserProcessesAsync(callback3
);
212 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
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
);
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() {
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
);
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() {
269 mController
.startBrowserProcessesAsync(callback1
);
272 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
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() {
299 mController
.startBrowserProcessesAsync(callback3
);
302 ThreadUtils
.runOnUiThreadBlocking(new Runnable() {
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
);
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() {
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());
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() {
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
);
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() {
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() {
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
);
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() {
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
);