Move idle detection classes to its own directory
Reviewed By: AaaChiuuu Differential Revision: D4676282 fbshipit-source-id: 1b07e66ba638d4293eec65cb4e336f21dfb78218
This commit is contained in:
parent
e69a80f7f9
commit
238fd4ad19
|
@ -2,7 +2,10 @@ include_defs("//ReactAndroid/DEFS")
|
|||
|
||||
android_library(
|
||||
name = "testing",
|
||||
srcs = glob(["**/*.java"]),
|
||||
srcs = glob(
|
||||
["**/*.java"],
|
||||
excludes = ["idledetection/**/*.java"],
|
||||
),
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
|
@ -25,5 +28,6 @@ android_library(
|
|||
react_native_target("java/com/facebook/react/modules/debug:interfaces"),
|
||||
react_native_target("java/com/facebook/react/shell:shell"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
react_native_integration_tests_target("java/com/facebook/react/testing/idledetection:idledetection"),
|
||||
],
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.view.ViewGroup;
|
|||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.testing.idledetection.IdleWaiter;
|
||||
|
||||
/**
|
||||
* Base class for instrumentation tests that runs React based react application in UI mode
|
||||
|
@ -123,7 +124,6 @@ public abstract class ReactAppInstrumentationTestCase extends
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
getActivity().runOnUiThread(getScreenshotRunnable);
|
||||
try {
|
||||
if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
|
||||
|
|
|
@ -28,6 +28,8 @@ import com.facebook.react.bridge.ReactContext;
|
|||
import com.facebook.react.common.LifecycleState;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.shell.MainReactPackage;
|
||||
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
|
||||
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
|
||||
public class ReactAppTestActivity extends FragmentActivity implements
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.testing;
|
||||
package com.facebook.react.testing.idledetection;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
|
|
@ -32,6 +32,8 @@ import com.facebook.react.common.ApplicationHolder;
|
|||
import com.facebook.react.common.futures.SimpleSettableFuture;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.modules.core.Timing;
|
||||
import com.facebook.react.testing.idledetection.ReactBridgeIdleSignaler;
|
||||
import com.facebook.react.testing.idledetection.ReactIdleDetectionUtil;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
|
|
@ -13,6 +13,8 @@ import android.view.MotionEvent;
|
|||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.facebook.react.testing.idledetection.IdleWaiter;
|
||||
|
||||
/**
|
||||
* Provides methods for generating touch events and dispatching them directly to a given view.
|
||||
* Events scenarios are based on {@link android.test.TouchUtils} but they get gets dispatched
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
include_defs("//ReactAndroid/DEFS")
|
||||
|
||||
android_library(
|
||||
name = "idledetection",
|
||||
srcs = glob(["**/*.java"]),
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
react_native_dep("third-party/java/testing-support-lib:runner"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/modules/core:core"),
|
||||
],
|
||||
)
|
|
@ -6,7 +6,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.testing;
|
||||
package com.facebook.react.testing.idledetection;
|
||||
|
||||
/**
|
||||
* Interface for something that knows how to wait for bridge and UI idle.
|
|
@ -6,7 +6,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.testing;
|
||||
package com.facebook.react.testing.idledetection;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.testing.idledetection;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.os.SystemClock;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.modules.core.ChoreographerCompat;
|
||||
|
||||
public class ReactIdleDetectionUtil {
|
||||
|
||||
/**
|
||||
* Waits for both the UI thread and bridge to be idle. It determines this by waiting for the
|
||||
* bridge to become idle, then waiting for the UI thread to become idle, then checking if the
|
||||
* bridge is idle again (if the bridge was idle before and is still idle after running the UI
|
||||
* thread to idle, then there are no more events to process in either place).
|
||||
* <p/>
|
||||
* Also waits for any Choreographer callbacks to run after the initial sync since things like UI
|
||||
* events are initiated from Choreographer callbacks.
|
||||
*/
|
||||
public static void waitForBridgeAndUIIdle(
|
||||
ReactBridgeIdleSignaler idleSignaler,
|
||||
final ReactContext reactContext,
|
||||
long timeoutMs) {
|
||||
UiThreadUtil.assertNotOnUiThread();
|
||||
|
||||
long startTime = SystemClock.uptimeMillis();
|
||||
waitInner(idleSignaler, timeoutMs);
|
||||
|
||||
long timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
|
||||
waitForChoreographer(timeToWait);
|
||||
waitForJSIdle(reactContext);
|
||||
|
||||
timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
|
||||
waitInner(idleSignaler, timeToWait);
|
||||
timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
|
||||
waitForChoreographer(timeToWait);
|
||||
}
|
||||
|
||||
private static void waitForChoreographer(long timeToWait) {
|
||||
final int waitFrameCount = 2;
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
UiThreadUtil.runOnUiThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ChoreographerCompat.getInstance().postFrameCallback(
|
||||
new ChoreographerCompat.FrameCallback() {
|
||||
|
||||
private int frameCount = 0;
|
||||
|
||||
@Override
|
||||
public void doFrame(long frameTimeNanos) {
|
||||
frameCount++;
|
||||
if (frameCount == waitFrameCount) {
|
||||
latch.countDown();
|
||||
} else {
|
||||
ChoreographerCompat.getInstance().postFrameCallback(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
try {
|
||||
if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) {
|
||||
throw new RuntimeException("Timed out waiting for Choreographer");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitForJSIdle(ReactContext reactContext) {
|
||||
if (!reactContext.hasActiveCatalystInstance()) {
|
||||
return;
|
||||
}
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
reactContext.runOnJSQueueThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
|
||||
throw new RuntimeException("Timed out waiting for JS thread");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) {
|
||||
// TODO gets broken in gradle, do we need it?
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
long startTime = SystemClock.uptimeMillis();
|
||||
boolean bridgeWasIdle = false;
|
||||
while (SystemClock.uptimeMillis() - startTime < timeToWait) {
|
||||
boolean bridgeIsIdle = idleSignaler.isBridgeIdle();
|
||||
if (bridgeIsIdle && bridgeWasIdle) {
|
||||
return;
|
||||
}
|
||||
bridgeWasIdle = bridgeIsIdle;
|
||||
long newTimeToWait = Math.max(1, timeToWait - (SystemClock.uptimeMillis() - startTime));
|
||||
idleSignaler.waitForIdle(newTimeToWait);
|
||||
instrumentation.waitForIdleSync();
|
||||
}
|
||||
throw new RuntimeException("Timed out waiting for bridge and UI idle!");
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ deps = [
|
|||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_dep("third-party/java/junit:junit"),
|
||||
react_native_integration_tests_target("java/com/facebook/react/testing:testing"),
|
||||
react_native_integration_tests_target("java/com/facebook/react/testing/idledetection:idledetection"),
|
||||
react_native_target("java/com/facebook/react:react"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
|
|
Loading…
Reference in New Issue