Files
Lawnchair/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
T
vadimt 053cb7a6e6 Not crashing tests when a test fails to deinitialize
This causes nondescript diags "Test failed to run to completion.
Reason: 'Instrumentation run failed due to 'Process crashed.''. Check
device logcat for details"

Now quietly skipping all consequent tests after such failure.

Change-Id: I3747cda1a3094bfe82e27eae39ba9e9dfd4af9b6
2020-01-27 19:26:00 -08:00

93 lines
3.2 KiB
Java

package com.android.launcher3.util.rule;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import android.util.Log;
import androidx.test.uiautomator.UiDevice;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
public class FailureWatcher extends TestWatcher {
private static final String TAG = "FailureWatcher";
private static boolean sHadFailedTestDeinitialization;
final private UiDevice mDevice;
public FailureWatcher(UiDevice device) {
mDevice = device;
}
private static void dumpViewHierarchy(UiDevice device) {
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
device.dumpWindowHierarchy(stream);
stream.flush();
stream.close();
for (String line : stream.toString().split("\\r?\\n")) {
Log.e(TAG, line.trim());
}
} catch (IOException e) {
Log.e(TAG, "error dumping XML to logcat", e);
}
}
@Override
protected void failed(Throwable e, Description description) {
onError(mDevice, description, e);
}
public static void onError(UiDevice device, Description description, Throwable e) {
if (device == null) return;
final String pathname = getInstrumentation().getTargetContext().
getFilesDir().getPath() + "/TestScreenshot-" + description.getMethodName()
+ ".png";
Log.e(TAG, "Failed test " + description.getMethodName() +
", screenshot will be saved to " + pathname +
", track trace is below, UI object dump is further below:\n" +
Log.getStackTraceString(e));
dumpViewHierarchy(device);
try {
final String dumpsysResult = device.executeShellCommand(
"dumpsys activity service TouchInteractionService");
Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
} catch (IOException ex) {
}
device.takeScreenshot(new File(pathname));
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
if (sHadFailedTestDeinitialization) {
Log.d(TAG, "Skipping due to a recent test deinitialization failure: " +
description.getDisplayName());
return;
}
try {
base.evaluate();
} catch (Throwable e) {
if (!Log.getStackTraceString(e).contains(
"androidx.test.internal.runner.junit4.statement.RunBefores.evaluate")) {
// Test failed to deinitialize. Since the global state is probably
// corrupted, won't execute other tests.
sHadFailedTestDeinitialization = true;
}
throw e;
}
}
};
}
}