diff options
author | Stefan Andonian <andonian@google.com> | 2023-04-21 19:05:47 +0000 |
---|---|---|
committer | Stefan Andonian <andonian@google.com> | 2023-05-12 21:15:14 +0000 |
commit | fa8091661ac1cef2ebdb830be0f1bd3fee13652b (patch) | |
tree | 9aaed6e05b7936e36a3068db69f439eb63f0562c /tests | |
parent | 4d559a6c921d6bb5adf16d9a7b1ad37f2a980581 (diff) | |
download | Launcher3-fa8091661ac1cef2ebdb830be0f1bd3fee13652b.tar.gz |
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
Diffstat (limited to 'tests')
6 files changed, 111 insertions, 12 deletions
diff --git a/tests/Android.bp b/tests/Android.bp index fa0cdf270b..e7f408487d 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -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, - }
\ No newline at end of file + } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 3141c7ba12..d7c4ae3857 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -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 diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java index 51facf49ab..19e7b13e33 100644 --- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java +++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java @@ -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 diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java index 2093682373..e9a52f84df 100644 --- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java +++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java @@ -56,4 +56,4 @@ public class LauncherActivityRule extends SimpleActivityRule<Launcher> { return launcher.getWorkspace().getFirstMatch(op) != null; }; } -} +}
\ No newline at end of file diff --git a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java index 1dbba6a1f6..2eedec30b6 100644 --- a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java +++ b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java @@ -102,4 +102,4 @@ public class SimpleActivityRule<T extends Activity> implements TestRule { } } } -} +}
\ No newline at end of file diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt new file mode 100644 index 0000000000..e4713b2e8b --- /dev/null +++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt @@ -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) + } + } + } + } +} |