mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-05 22:38:59 +08:00
Android Instrumentations tests are ready to be run in github/CI open source environment
Reviewed By: mkonicek Differential Revision: D2769217 fb-gh-sync-id: 7469af816241d8b642753cca21f6542b971e9572
This commit is contained in:
committed by
facebook-github-bot-9
parent
040909904c
commit
a99c5160ee
@@ -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;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.os.SystemClock;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.view.Choreographer;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
|
||||
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.elapsedRealtime();
|
||||
waitInner(idleSignaler, timeoutMs);
|
||||
|
||||
long timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
|
||||
waitForChoreographer(timeToWait);
|
||||
waitForJSIdle(reactContext);
|
||||
|
||||
timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - startTime));
|
||||
waitInner(idleSignaler, timeToWait);
|
||||
timeToWait = Math.max(1, timeoutMs - (SystemClock.elapsedRealtime() - 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() {
|
||||
Choreographer.getInstance().postFrameCallback(
|
||||
new Choreographer.FrameCallback() {
|
||||
|
||||
private int frameCount = 0;
|
||||
|
||||
@Override
|
||||
public void doFrame(long frameTimeNanos) {
|
||||
frameCount++;
|
||||
if (frameCount == waitFrameCount) {
|
||||
latch.countDown();
|
||||
} else {
|
||||
Choreographer.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.elapsedRealtime();
|
||||
boolean bridgeWasIdle = false;
|
||||
while (SystemClock.elapsedRealtime() - startTime < timeToWait) {
|
||||
boolean bridgeIsIdle = idleSignaler.isBridgeIdle();
|
||||
if (bridgeIsIdle && bridgeWasIdle) {
|
||||
return;
|
||||
}
|
||||
bridgeWasIdle = bridgeIsIdle;
|
||||
long newTimeToWait = Math.max(1, timeToWait - (SystemClock.elapsedRealtime() - startTime));
|
||||
idleSignaler.waitForIdle(newTimeToWait);
|
||||
instrumentation.waitForIdleSync();
|
||||
}
|
||||
throw new RuntimeException("Timed out waiting for bridge and UI idle!");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user