6c416c699d
This is based on the brainstorm "diagnostic scripts running on ATP". Please propose additional (to "TestRunner") tags. Also adding class name to all artifact filenames because sometimes different classes have failing tests with the same name. Bug: 197991109 Test: local runs Change-Id: Ic2022ca526d833fe99450e90fcfd8fb7be1f79d5
133 lines
5.0 KiB
Java
133 lines
5.0 KiB
Java
package com.android.launcher3.util.rule;
|
|
|
|
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
|
|
|
import android.os.FileUtils;
|
|
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
|
|
import android.util.Log;
|
|
|
|
import androidx.test.uiautomator.UiDevice;
|
|
|
|
import com.android.launcher3.tapl.LauncherInstrumentation;
|
|
import com.android.launcher3.ui.AbstractLauncherUiTest;
|
|
|
|
import org.junit.rules.TestWatcher;
|
|
import org.junit.runner.Description;
|
|
import org.junit.runners.model.Statement;
|
|
|
|
import java.io.BufferedOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipOutputStream;
|
|
|
|
public class FailureWatcher extends TestWatcher {
|
|
private static final String TAG = "FailureWatcher";
|
|
final private UiDevice mDevice;
|
|
private final LauncherInstrumentation mLauncher;
|
|
|
|
public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) {
|
|
mDevice = device;
|
|
mLauncher = launcher;
|
|
Log.d("b/196820244", "FailureWatcher.ctor", new Exception());
|
|
}
|
|
|
|
@Override
|
|
protected void succeeded(Description description) {
|
|
super.succeeded(description);
|
|
AbstractLauncherUiTest.checkDetectedLeaks(mLauncher);
|
|
}
|
|
|
|
@Override
|
|
public Statement apply(Statement base, Description description) {
|
|
return new Statement() {
|
|
@Override
|
|
public void evaluate() throws Throwable {
|
|
try {
|
|
Log.d("b/196820244", "Before evaluate");
|
|
FailureWatcher.super.apply(base, description).evaluate();
|
|
Log.d("b/196820244", "After evaluate");
|
|
} finally {
|
|
if (mLauncher.hadNontestEvents()) {
|
|
throw new AssertionError(
|
|
"Launcher received events not sent by the test. This may mean "
|
|
+ "that the touch screen of the lab device has sent false"
|
|
+ " events. See the logcat for TaplEvents tag and look "
|
|
+ "for events with deviceId != -1");
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
protected void failed(Throwable e, Description description) {
|
|
onError(mDevice, description, e);
|
|
}
|
|
|
|
static File diagFile(Description description, String prefix, String ext) {
|
|
return new File(getInstrumentation().getTargetContext().getFilesDir(),
|
|
prefix + "-" + description.getTestClass().getSimpleName() + "."
|
|
+ description.getMethodName() + "." + ext);
|
|
}
|
|
|
|
public static void onError(UiDevice device, Description description, Throwable e) {
|
|
Log.d("b/196820244", "onError 1");
|
|
if (device == null) return;
|
|
Log.d("b/196820244", "onError 2");
|
|
final File sceenshot = diagFile(description, "TestScreenshot", "png");
|
|
final File hierarchy = diagFile(description, "Hierarchy", "zip");
|
|
|
|
// Dump window hierarchy
|
|
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(hierarchy))) {
|
|
out.putNextEntry(new ZipEntry("bugreport.txt"));
|
|
dumpStringCommand("dumpsys window windows", out);
|
|
dumpStringCommand("dumpsys package", out);
|
|
dumpStringCommand("dumpsys activity service TouchInteractionService", out);
|
|
out.closeEntry();
|
|
|
|
out.putNextEntry(new ZipEntry("visible_windows.zip"));
|
|
dumpCommand("cmd window dump-visible-window-views", out);
|
|
out.closeEntry();
|
|
} catch (IOException ex) {
|
|
}
|
|
|
|
Log.e(TAG, "Failed test " + description.getMethodName()
|
|
+ ",\nscreenshot will be saved to " + sceenshot
|
|
+ ",\nUI dump at: " + hierarchy
|
|
+ " (use go/web-hv to open the dump file)", e);
|
|
device.takeScreenshot(sceenshot);
|
|
|
|
// Dump accessibility hierarchy
|
|
try {
|
|
device.dumpWindowHierarchy(diagFile(description, "AccessibilityHierarchy", "uix"));
|
|
} catch (IOException ex) {
|
|
Log.e(TAG, "Failed to save accessibility hierarchy", ex);
|
|
}
|
|
|
|
dumpCommand("logcat -d -s TestRunner", diagFile(description, "FilteredLogcat", "txt"));
|
|
}
|
|
|
|
private static void dumpStringCommand(String cmd, OutputStream out) throws IOException {
|
|
out.write(("\n\n" + cmd + "\n").getBytes());
|
|
dumpCommand(cmd, out);
|
|
}
|
|
|
|
private static void dumpCommand(String cmd, File out) {
|
|
try (BufferedOutputStream buffered = new BufferedOutputStream(
|
|
new FileOutputStream(out))) {
|
|
dumpCommand(cmd, buffered);
|
|
} catch (IOException ex) {
|
|
}
|
|
}
|
|
|
|
private static void dumpCommand(String cmd, OutputStream out) throws IOException {
|
|
try (AutoCloseInputStream in = new AutoCloseInputStream(getInstrumentation()
|
|
.getUiAutomation().executeShellCommand(cmd))) {
|
|
FileUtils.copy(in, out);
|
|
}
|
|
}
|
|
}
|