mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-19 18:58:19 +00:00
Added ViewCapture to all tests which implement AbstractLauncherUiTest.
This enables developers to watch failed tests in classes like TaplTestsQuickstep in the go/web-hv tool. Bug: 242867462 Test: Failed a test and verified that the TimeLapse bugreport entry showed up properly in the go/web-hv tool. Change-Id: Ic89af2a0e7102db52c52ddc668607a81c4809ed6
This commit is contained in:
@@ -62,6 +62,7 @@ import com.android.launcher3.util.rule.FailureWatcher;
|
||||
import com.android.launcher3.util.rule.SamplerRule;
|
||||
import com.android.launcher3.util.rule.ScreenRecordRule;
|
||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||
import com.android.launcher3.util.rule.ViewCaptureRule;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -115,10 +116,12 @@ public class FallbackRecentsTest {
|
||||
Utilities.enableRunningInTestHarnessForTests();
|
||||
}
|
||||
|
||||
final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
|
||||
mOrderSensitiveRules = RuleChain
|
||||
.outerRule(new SamplerRule())
|
||||
.around(new NavigationModeSwitchRule(mLauncher))
|
||||
.around(new FailureWatcher(mDevice, mLauncher));
|
||||
.around(viewCaptureRule)
|
||||
.around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()));
|
||||
|
||||
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
|
||||
getHomeIntentInPackage(context),
|
||||
|
||||
@@ -51,6 +51,7 @@ filegroup {
|
||||
"src/com/android/launcher3/util/WidgetUtils.java",
|
||||
"src/com/android/launcher3/util/rule/FailureWatcher.java",
|
||||
"src/com/android/launcher3/util/rule/LauncherActivityRule.java",
|
||||
"src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
|
||||
"src/com/android/launcher3/util/rule/SamplerRule.java",
|
||||
"src/com/android/launcher3/util/rule/ScreenRecordRule.java",
|
||||
"src/com/android/launcher3/util/rule/ShellCommandRule.java",
|
||||
@@ -132,4 +133,4 @@ android_library {
|
||||
manifest: "shared/AndroidManifest.xml",
|
||||
sdk_version: "current",
|
||||
min_sdk_version: min_launcher3_sdk_version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ import com.android.launcher3.util.rule.SamplerRule;
|
||||
import com.android.launcher3.util.rule.ScreenRecordRule;
|
||||
import com.android.launcher3.util.rule.ShellCommandRule;
|
||||
import com.android.launcher3.util.rule.TestStabilityRule;
|
||||
import com.android.launcher3.util.rule.ViewCaptureRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
@@ -215,14 +216,15 @@ public abstract class AbstractLauncherUiTest {
|
||||
}
|
||||
|
||||
protected TestRule getRulesInsideActivityMonitor() {
|
||||
final ViewCaptureRule viewCaptureRule = new ViewCaptureRule();
|
||||
final RuleChain inner = RuleChain
|
||||
.outerRule(new PortraitLandscapeRunner(this))
|
||||
.around(new FailureWatcher(mDevice, mLauncher));
|
||||
.around(viewCaptureRule)
|
||||
.around(new FailureWatcher(mDevice, mLauncher, viewCaptureRule.getViewCapture()));
|
||||
|
||||
return TestHelpers.isInLauncherProcess()
|
||||
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher())
|
||||
.around(inner) :
|
||||
inner;
|
||||
? RuleChain.outerRule(ShellCommandRule.setDefaultLauncher()).around(inner)
|
||||
: inner;
|
||||
}
|
||||
|
||||
@Rule
|
||||
|
||||
@@ -7,8 +7,12 @@ import android.os.FileUtils;
|
||||
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.app.viewcapture.ViewCapture;
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.ui.AbstractLauncherUiTest;
|
||||
|
||||
@@ -29,10 +33,14 @@ public class FailureWatcher extends TestWatcher {
|
||||
private static boolean sSavedBugreport = false;
|
||||
final private UiDevice mDevice;
|
||||
private final LauncherInstrumentation mLauncher;
|
||||
@NonNull
|
||||
private final ViewCapture mViewCapture;
|
||||
|
||||
public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) {
|
||||
public FailureWatcher(UiDevice device, LauncherInstrumentation launcher,
|
||||
@NonNull ViewCapture viewCapture) {
|
||||
mDevice = device;
|
||||
mLauncher = launcher;
|
||||
mViewCapture = viewCapture;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,7 +90,7 @@ public class FailureWatcher extends TestWatcher {
|
||||
|
||||
@Override
|
||||
protected void failed(Throwable e, Description description) {
|
||||
onError(mLauncher, description, e);
|
||||
onError(mLauncher, description, e, mViewCapture);
|
||||
}
|
||||
|
||||
static File diagFile(Description description, String prefix, String ext) {
|
||||
@@ -93,8 +101,12 @@ public class FailureWatcher extends TestWatcher {
|
||||
|
||||
public static void onError(LauncherInstrumentation launcher, Description description,
|
||||
Throwable e) {
|
||||
final UiDevice device = launcher.getDevice();
|
||||
if (device == null) return;
|
||||
onError(launcher, description, e, null);
|
||||
}
|
||||
|
||||
private static void onError(LauncherInstrumentation launcher, Description description,
|
||||
Throwable e, @Nullable ViewCapture viewCapture) {
|
||||
|
||||
final File sceenshot = diagFile(description, "TestScreenshot", "png");
|
||||
final File hierarchy = diagFile(description, "Hierarchy", "zip");
|
||||
|
||||
@@ -109,13 +121,20 @@ public class FailureWatcher extends TestWatcher {
|
||||
out.putNextEntry(new ZipEntry("visible_windows.zip"));
|
||||
dumpCommand("cmd window dump-visible-window-views", out);
|
||||
out.closeEntry();
|
||||
} catch (IOException ex) {
|
||||
|
||||
if (viewCapture != null) {
|
||||
out.putNextEntry(new ZipEntry("FS/data/misc/wmtrace/failed_test.vc"));
|
||||
viewCapture.dumpTo(out, ApplicationProvider.getApplicationContext());
|
||||
out.closeEntry();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
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);
|
||||
final UiDevice device = launcher.getDevice();
|
||||
device.takeScreenshot(sceenshot);
|
||||
|
||||
// Dump accessibility hierarchy
|
||||
|
||||
@@ -56,4 +56,4 @@ public class LauncherActivityRule extends SimpleActivityRule<Launcher> {
|
||||
return launcher.getWorkspace().getFirstMatch(op) != null;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,4 +102,4 @@ public class SimpleActivityRule<T extends Activity> implements TestRule {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
77
tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
Normal file
77
tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.android.launcher3.util.rule
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.media.permission.SafeCloseable
|
||||
import android.os.Bundle
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.android.app.viewcapture.SimpleViewCapture
|
||||
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
|
||||
/**
|
||||
* This JUnit TestRule registers a listener for activity lifecycle events to attach a ViewCapture
|
||||
* instance that other test rules use to dump the timelapse hierarchy upon an error during a test.
|
||||
*
|
||||
* This rule will not work in OOP tests that don't have access to the activity under test.
|
||||
*/
|
||||
class ViewCaptureRule : TestRule {
|
||||
val viewCapture = SimpleViewCapture("test-view-capture")
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement {
|
||||
return object : Statement() {
|
||||
override fun evaluate() {
|
||||
val windowListenerCloseables = mutableListOf<SafeCloseable>()
|
||||
|
||||
val lifecycleCallbacks =
|
||||
object : ActivityLifecycleCallbacksAdapter {
|
||||
override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
|
||||
super.onActivityCreated(activity, bundle)
|
||||
windowListenerCloseables.add(
|
||||
viewCapture.startCapture(
|
||||
activity.window.decorView,
|
||||
"${description.testClass?.simpleName}.${description.methodName}"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
super.onActivityDestroyed(activity)
|
||||
viewCapture.stopCapture(activity.window.decorView)
|
||||
}
|
||||
}
|
||||
|
||||
val application = ApplicationProvider.getApplicationContext<Application>()
|
||||
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
|
||||
|
||||
try {
|
||||
base.evaluate()
|
||||
} finally {
|
||||
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
|
||||
|
||||
// Clean up ViewCapture references here rather than in onActivityDestroyed so
|
||||
// test code can access view hierarchy capture. onActivityDestroyed would delete
|
||||
// view capture data before FailureWatcher could output it as a test artifact.
|
||||
windowListenerCloseables.onEach(SafeCloseable::close)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user