Move idle detection classes to its own directory

Reviewed By: AaaChiuuu

Differential Revision: D4676282

fbshipit-source-id: 1b07e66ba638d4293eec65cb4e336f21dfb78218
This commit is contained in:
Andrew Y. Chen 2017-03-17 16:30:27 -07:00 committed by Facebook Github Bot
parent e69a80f7f9
commit 238fd4ad19
11 changed files with 155 additions and 5 deletions

View File

@ -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"),
],
)

View File

@ -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)) {

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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"),
],
)

View File

@ -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.

View File

@ -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;

View File

@ -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!");
}
}

View File

@ -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"),