Commit 0facf065 authored by Ted Choc's avatar Ted Choc Committed by Commit Bot

Add tests for DeferredStartupHandler.

BUG=702154

Change-Id: Ic5b338b9c4a59be0d777b38c6341d9ca293ba9bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2131152
Commit-Queue: Ted Choc <tedchoc@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarPeter Wen <wnwen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#755937}
parent 2d9be659
...@@ -2,11 +2,13 @@ chrome_junit_test_java_sources = [ ...@@ -2,11 +2,13 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/AppIndexingUtilTest.java", "junit/src/org/chromium/chrome/browser/AppIndexingUtilTest.java",
"junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerTest.java", "junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerTest.java",
"junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java", "junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java",
"junit/src/org/chromium/chrome/browser/DeferredStartupHandlerTest.java",
"junit/src/org/chromium/chrome/browser/DelayedScreenLockIntentHandlerTest.java", "junit/src/org/chromium/chrome/browser/DelayedScreenLockIntentHandlerTest.java",
"junit/src/org/chromium/chrome/browser/DeviceConditionsTest.java", "junit/src/org/chromium/chrome/browser/DeviceConditionsTest.java",
"junit/src/org/chromium/chrome/browser/IntentHeadersRecorderTest.java", "junit/src/org/chromium/chrome/browser/IntentHeadersRecorderTest.java",
"junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java",
"junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java", "junit/src/org/chromium/chrome/browser/ShadowDeviceConditions.java",
"junit/src/org/chromium/chrome/browser/ShadowIdleHandlerAwareMessageQueue.java",
"junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java", "junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java",
"junit/src/org/chromium/chrome/browser/about_settings/AboutSettingsBridgeTest.java", "junit/src/org/chromium/chrome/browser/about_settings/AboutSettingsBridgeTest.java",
"junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java",
......
...@@ -5,12 +5,10 @@ ...@@ -5,12 +5,10 @@
package org.chromium.chrome.browser; package org.chromium.chrome.browser;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import java.util.LinkedList; import java.util.LinkedList;
...@@ -25,8 +23,7 @@ public class DeferredStartupHandler { ...@@ -25,8 +23,7 @@ public class DeferredStartupHandler {
private static final DeferredStartupHandler INSTANCE = new DeferredStartupHandler(); private static final DeferredStartupHandler INSTANCE = new DeferredStartupHandler();
} }
private boolean mDeferredStartupCompletedForApp; private Boolean mDeferredStartupCompletedAllPendingTasks;
private final Context mAppContext;
private final Queue<Runnable> mDeferredTasks; private final Queue<Runnable> mDeferredTasks;
...@@ -47,7 +44,6 @@ public class DeferredStartupHandler { ...@@ -47,7 +44,6 @@ public class DeferredStartupHandler {
private static DeferredStartupHandler sDeferredStartupHandler; private static DeferredStartupHandler sDeferredStartupHandler;
protected DeferredStartupHandler() { protected DeferredStartupHandler() {
mAppContext = ContextUtils.getApplicationContext();
mDeferredTasks = new LinkedList<>(); mDeferredTasks = new LinkedList<>();
} }
...@@ -57,11 +53,18 @@ public class DeferredStartupHandler { ...@@ -57,11 +53,18 @@ public class DeferredStartupHandler {
* tasks. * tasks.
*/ */
public void queueDeferredTasksOnIdleHandler() { public void queueDeferredTasksOnIdleHandler() {
// Ensure only a single IdleHandler is added at any given time.
if (mDeferredStartupCompletedAllPendingTasks != null
&& !mDeferredStartupCompletedAllPendingTasks) {
return;
}
mDeferredStartupCompletedAllPendingTasks = false;
Looper.myQueue().addIdleHandler(() -> { Looper.myQueue().addIdleHandler(() -> {
Runnable currentTask = mDeferredTasks.poll(); Runnable currentTask = mDeferredTasks.poll();
if (currentTask == null) { if (currentTask == null) {
if (!mDeferredStartupCompletedForApp) { if (!mDeferredStartupCompletedAllPendingTasks) {
mDeferredStartupCompletedForApp = true; mDeferredStartupCompletedAllPendingTasks = true;
} }
return false; return false;
} }
...@@ -86,6 +89,7 @@ public class DeferredStartupHandler { ...@@ -86,6 +89,7 @@ public class DeferredStartupHandler {
*/ */
@VisibleForTesting @VisibleForTesting
public boolean isDeferredStartupCompleteForApp() { public boolean isDeferredStartupCompleteForApp() {
return mDeferredStartupCompletedForApp; return mDeferredStartupCompletedAllPendingTasks != null
&& mDeferredStartupCompletedAllPendingTasks;
} }
} }
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser;
import android.os.Looper;
import android.os.MessageQueue.IdleHandler;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.testing.local.LocalRobolectricTestRunner;
/**
* Unit tests for DeferredStartupHandler.
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {ShadowIdleHandlerAwareMessageQueue.class})
public class DeferredStartupHandlerTest {
private DeferredStartupHandler mDeferredStartupHandler;
private ShadowIdleHandlerAwareMessageQueue mShadowMessageQueue;
@Before
public void setUp() {
mShadowMessageQueue = (ShadowIdleHandlerAwareMessageQueue) Shadow.extract(Looper.myQueue());
mShadowMessageQueue.clearIdleHandlers();
mDeferredStartupHandler = new DeferredStartupHandler();
}
@Test
public void addDeferredTask_SingleTask() {
CallbackHelper helper = new CallbackHelper();
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
Assert.assertEquals(0, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(0, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
}
@Test
public void addDeferredTask_MultipleTask() {
CallbackHelper helper = new CallbackHelper();
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
Assert.assertEquals(0, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(2, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(3, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(3, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
}
@Test
public void addDeferredTask_WhileIdleHandlerRunning() {
CallbackHelper helper = new CallbackHelper();
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
Assert.assertEquals(0, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
// Add a new deferred task.
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
// The subsequent IdleHandler pass should run the newly added task.
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(2, helper.getCallCount());
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(2, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
}
@Test
public void addDeferredTask_AfterIdleHandlerRan() {
CallbackHelper helper = new CallbackHelper();
mDeferredStartupHandler.addDeferredTask(() -> helper.notifyCalled());
Assert.assertEquals(0, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
// Add a new task.
CallbackHelper helper2 = new CallbackHelper();
mDeferredStartupHandler.addDeferredTask(() -> helper2.notifyCalled());
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(0, helper2.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
// Ensure a new request to queue can process these tasks.
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
mShadowMessageQueue.runIdleHandlers();
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(1, helper.getCallCount());
Assert.assertEquals(1, helper2.getCallCount());
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
}
@Test
public void queueDeferredTasksOnIdleHandler_OnlyOneIdleHandler() {
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
IdleHandler initialIdleHandler = mShadowMessageQueue.getIdleHandlers().get(0);
// Ensure a second call to queueDeferredTasksOnIdleHandler does not add another IdleHandler.
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
Assert.assertEquals(initialIdleHandler, mShadowMessageQueue.getIdleHandlers().get(0));
mShadowMessageQueue.runIdleHandlers();
mShadowMessageQueue.runIdleHandlers();
Assert.assertEquals(0, mShadowMessageQueue.getIdleHandlers().size());
// Ensure a call queueDeferredTasksOnIdleHandler after the previous IdleHandler completes
// adds a new IdleHandler.
mDeferredStartupHandler.queueDeferredTasksOnIdleHandler();
Assert.assertEquals(1, mShadowMessageQueue.getIdleHandlers().size());
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser;
import android.os.MessageQueue;
import android.os.MessageQueue.IdleHandler;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowLegacyMessageQueue;
import java.util.ArrayList;
import java.util.List;
/**
* Shadow MessageQueue implementation that adds support for IdleHandler(s).
*/
@Implements(MessageQueue.class)
public class ShadowIdleHandlerAwareMessageQueue extends ShadowLegacyMessageQueue {
private final List<IdleHandler> mIdleHandlers = new ArrayList<>();
private final Object mIdleHandlersLock = new Object();
/** Default constructor needed by robolectric. */
public ShadowIdleHandlerAwareMessageQueue() {}
/** @see MessageQueue#addIdleHandler(IdleHandler) */
public void addIdleHandler(IdleHandler handler) {
synchronized (mIdleHandlersLock) {
mIdleHandlers.add(handler);
}
}
/** @see MessageQueue#removeIdleHandler(IdleHandler) */
public void removeIdleHandler(IdleHandler handler) {
synchronized (mIdleHandlersLock) {
mIdleHandlers.remove(handler);
}
}
/**
* Run all idle handlers.
*/
public void runIdleHandlers() {
List<IdleHandler> idleHandlers;
synchronized (mIdleHandlersLock) {
idleHandlers = new ArrayList<>(mIdleHandlers);
}
for (int i = 0; i < idleHandlers.size(); i++) {
IdleHandler handler = idleHandlers.get(i);
if (!handler.queueIdle()) removeIdleHandler(handler);
}
}
public List<IdleHandler> getIdleHandlers() {
return mIdleHandlers;
}
public void clearIdleHandlers() {
synchronized (mIdleHandlersLock) {
mIdleHandlers.clear();
}
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment