Bug 1553515 - Replace loopUntilIdle -> waitForCondition. r=snorp

Differential Revision: https://phabricator.services.mozilla.com/D32583

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Agi Sferro 2019-06-27 15:58:46 +00:00
Родитель 4f0dfa866e
Коммит b9b75a5400
6 изменённых файлов: 65 добавлений и 121 удалений

Просмотреть файл

@ -1,8 +1,7 @@
package org.mozilla.geckoview.test;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoResult.OnExceptionListener;
import org.mozilla.geckoview.GeckoResult.OnValueListener;
import org.mozilla.geckoview.test.util.Environment;
import org.mozilla.geckoview.test.util.UiThreadUtils;
@ -34,19 +33,11 @@ public class GeckoResultTest {
private void waitUntilDone() {
assertThat("We should not be done", mDone, equalTo(false));
while (!mDone) {
UiThreadUtils.loopUntilIdle(mEnv.getDefaultTimeoutMillis());
}
UiThreadUtils.waitForCondition(() -> mDone, mEnv.getDefaultTimeoutMillis());
}
private void done() {
UiThreadUtils.HANDLER.post(new Runnable() {
@Override
public void run() {
mDone = true;
}
});
UiThreadUtils.HANDLER.post(() -> mDone = true);
}
@Before

Просмотреть файл

@ -30,6 +30,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.test.util.HttpBin
import org.mozilla.geckoview.test.util.UiThreadUtils
import java.net.URI
@RunWith(AndroidJUnit4::class)
@ -1193,6 +1194,7 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.session.waitUntilCalled(GeckoSession.NavigationDelegate::class,
"onNewSession")
UiThreadUtils.loopUntilIdle(sessionRule.env.defaultTimeoutMillis)
}
@Test

Просмотреть файл

@ -481,20 +481,10 @@ class SessionLifecycleTest : BaseSessionTest() {
}
private fun waitUntilCollected(ref: QueuedWeakReference<*>) {
val start = SystemClock.uptimeMillis()
while (ref.queue.poll() == null) {
val elapsed = SystemClock.uptimeMillis() - start
if (elapsed > sessionRule.timeoutMillis) {
dumpHprof()
throw UiThreadUtils.TimeoutException("Timed out after " + elapsed + "ms")
}
try {
UiThreadUtils.loopUntilIdle(100)
} catch (e: UiThreadUtils.TimeoutException) {
}
UiThreadUtils.waitForCondition({
Runtime.getRuntime().gc()
}
ref.queue.poll() != null
}, sessionRule.timeoutMillis)
}
class QueuedWeakReference<T> @JvmOverloads constructor(obj: T, var queue: ReferenceQueue<T> =

Просмотреть файл

@ -1055,7 +1055,7 @@ public class GeckoSessionTestRule implements TestRule {
return new RuntimeException(cause != null ? cause : e);
}
protected void prepareStatement(final Description description) throws Throwable {
protected void prepareStatement(final Description description) {
final GeckoSessionSettings settings = new GeckoSessionSettings(mDefaultSettings);
mTimeoutMillis = env.getDefaultTimeoutMillis();
mNullDelegates = new HashSet<>();
@ -1195,9 +1195,13 @@ public class GeckoSessionTestRule implements TestRule {
}
}
protected void prepareSession(final GeckoSession session) throws Throwable {
protected void prepareSession(final GeckoSession session) {
for (final Class<?> cls : DEFAULT_DELEGATES) {
setDelegate(cls, session, mNullDelegates.contains(cls) ? null : mCallbackProxy);
try {
setDelegate(cls, session, mNullDelegates.contains(cls) ? null : mCallbackProxy);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
@ -1234,6 +1238,7 @@ public class GeckoSessionTestRule implements TestRule {
}
private void waitForInitialLoad(final GeckoSession session) {
ThreadUtils.assertOnUiThread();
// We receive an initial about:blank load; don't expose that to the test. The initial
// load ends with the first onPageStop call, so ignore everything from the session
// until the first onPageStop call.
@ -1295,7 +1300,7 @@ public class GeckoSessionTestRule implements TestRule {
}
}
protected void cleanupStatement() throws Throwable {
protected void cleanupStatement() {
mWaitScopeDelegates.clear();
mTestScopeDelegates.clear();
@ -1339,21 +1344,19 @@ public class GeckoSessionTestRule implements TestRule {
@Override
public void evaluate() throws Throwable {
final AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
mInstrumentation.runOnMainSync(() -> {
try {
prepareStatement(description);
base.evaluate();
performTestEndCheck();
} catch (Throwable t) {
exceptionRef.set(t);
} finally {
try {
prepareStatement(description);
base.evaluate();
performTestEndCheck();
cleanupStatement();
} catch (Throwable t) {
exceptionRef.set(t);
} finally {
try {
cleanupStatement();
} catch (Throwable t) {
exceptionRef.set(t);
}
exceptionRef.compareAndSet(null, t);
}
}
});
@ -1553,9 +1556,11 @@ public class GeckoSessionTestRule implements TestRule {
forCallbacksDuringWait(session, callback);
}
protected void waitUntilCalled(final @Nullable GeckoSession session,
final @NonNull Class<?> delegate,
final @NonNull List<MethodCall> methodCalls) {
private void waitUntilCalled(final @Nullable GeckoSession session,
final @NonNull Class<?> delegate,
final @NonNull List<MethodCall> methodCalls) {
ThreadUtils.assertOnUiThread();
if (session != null && !session.equals(mMainSession)) {
assertThat("Session should be wrapped through wrapSession",
session, isIn(mSubSessions));
@ -1602,15 +1607,8 @@ public class GeckoSessionTestRule implements TestRule {
beforeWait();
while (!calledAny || !methodCalls.isEmpty()) {
while (index >= mCallRecords.size()) {
UiThreadUtils.loopUntilIdle(mTimeoutMillis);
// We could loop forever here if the UI thread keeps receiving
// messages that don't result in any methods being called.
// Check whether we've exceeded our allotted time and bail out.
if (SystemClock.uptimeMillis() - startTime > mTimeoutMillis) {
break;
}
}
final int checkIndex = index;
UiThreadUtils.waitForCondition(() -> (checkIndex < mCallRecords.size()), mTimeoutMillis);
if (SystemClock.uptimeMillis() - startTime > mTimeoutMillis) {
throw new UiThreadUtils.TimeoutException("Timed out after " + mTimeoutMillis + "ms");

Просмотреть файл

@ -5,11 +5,13 @@ import org.mozilla.geckoview.GeckoRuntimeSettings;
import org.mozilla.geckoview.test.TestCrashHandler;
import android.os.Process;
import android.support.annotation.UiThread;
import android.support.test.InstrumentationRegistry;
public class RuntimeCreator {
private static GeckoRuntime sRuntime;
@UiThread
public static GeckoRuntime getRuntime() {
if (sRuntime != null) {
return sRuntime;
@ -30,12 +32,7 @@ public class RuntimeCreator {
InstrumentationRegistry.getTargetContext(),
runtimeSettingsBuilder.build());
sRuntime.setDelegate(new GeckoRuntime.Delegate() {
@Override
public void onShutdown() {
Process.killProcess(Process.myPid());
}
});
sRuntime.setDelegate(() -> Process.killProcess(Process.myPid()));
return sRuntime;
}

Просмотреть файл

@ -5,6 +5,7 @@
package org.mozilla.geckoview.test.util;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.GeckoResult;
import android.os.Handler;
@ -13,15 +14,16 @@ import android.os.Message;
import android.os.MessageQueue;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.internal.runner.InstrumentationConnection;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
public class UiThreadUtils {
private static final String LOGTAG = "UiThreadUtils";
private static long sLongestWait;
private static Method sGetNextMessage = null;
static {
try {
@ -59,16 +61,6 @@ public class UiThreadUtils {
public static final Handler HANDLER = new Handler(Looper.getMainLooper());
private static final TimeoutRunnable TIMEOUT_RUNNABLE = new TimeoutRunnable();
private static final MessageQueue.IdleHandler IDLE_HANDLER = new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
final Message msg = Message.obtain(HANDLER);
msg.obj = HANDLER;
HANDLER.sendMessageAtFrontOfQueue(msg);
return false; // Remove this idle handler.
}
};
private static RuntimeException unwrapRuntimeException(final Throwable e) {
final Throwable cause = e.getCause();
if (cause != null && cause instanceof RuntimeException) {
@ -91,9 +83,7 @@ public class UiThreadUtils {
public static <T> T waitForResult(@NonNull GeckoResult<T> result, long timeout) throws Throwable {
final ResultHolder<T> holder = new ResultHolder<>(result);
while (!holder.isComplete) {
loopUntilIdle(timeout);
}
waitForCondition(() -> holder.isComplete, timeout);
if (holder.error != null) {
throw holder.error;
@ -122,6 +112,27 @@ public class UiThreadUtils {
boolean test();
}
public static void loopUntilIdle(final long timeout) {
AtomicBoolean idle = new AtomicBoolean(false);
MessageQueue.IdleHandler handler = null;
try {
handler = () -> {
idle.set(true);
// Remove handler
return false;
};
HANDLER.getLooper().getQueue().addIdleHandler(handler);
waitForCondition(() -> idle.get(), timeout);
} finally {
if (handler != null) {
HANDLER.getLooper().getQueue().removeIdleHandler(handler);
}
}
}
public static void waitForCondition(Condition condition, final long timeout) {
// Adapted from GeckoThread.pumpMessageLoop.
final MessageQueue queue = HANDLER.getLooper().getQueue();
@ -146,49 +157,4 @@ public class UiThreadUtils {
TIMEOUT_RUNNABLE.cancel();
}
}
public static void loopUntilIdle(final long timeout) {
// Adapted from GeckoThread.pumpMessageLoop.
final MessageQueue queue = HANDLER.getLooper().getQueue();
if (timeout > 0) {
TIMEOUT_RUNNABLE.set(timeout);
} else {
queue.addIdleHandler(IDLE_HANDLER);
}
final long startTime = SystemClock.uptimeMillis();
try {
while (true) {
final Message msg;
try {
msg = (Message) sGetNextMessage.invoke(queue);
} catch (final IllegalAccessException | InvocationTargetException e) {
throw unwrapRuntimeException(e);
}
if (msg.getTarget() == HANDLER && msg.obj == HANDLER) {
// Our idle signal.
break;
} else if (msg.getTarget() == null) {
HANDLER.getLooper().quit();
return;
}
msg.getTarget().dispatchMessage(msg);
if (timeout > 0) {
TIMEOUT_RUNNABLE.cancel();
queue.addIdleHandler(IDLE_HANDLER);
}
}
final long waitDuration = SystemClock.uptimeMillis() - startTime;
if (waitDuration > sLongestWait) {
sLongestWait = waitDuration;
Log.i(LOGTAG, "New longest wait: " + waitDuration + "ms");
}
} finally {
if (timeout > 0) {
TIMEOUT_RUNNABLE.cancel();
}
}
}
}