aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRakib Hasan <rmhasan@google.com>2022-04-05 20:11:45 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-04-05 20:11:45 +0000
commit742a7d637010ac053bdb88541e104f2723759a12 (patch)
tree088f94c7fe081e037432dac7fb0c7cb1a68f320d
parent8133a36a7cdec64233c986a3762dafe7ff31cf7f (diff)
parentdefb3fe1b6c5497a6cb71365f8ef86ce60e3784a (diff)
downloadcsuite-742a7d637010ac053bdb88541e104f2723759a12.tar.gz
Merge "Add the initial webview app launch test module" am: 3cebfd8c08 am: defb3fe1b6
Original change: https://android-review.googlesource.com/c/platform/test/app_compat/csuite/+/2039135 Change-Id: I05e68acea0df2c04160fb9585a9dcb521fc0c65e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--test_scripts/src/main/java/com/android/webview/OWNERS2
-rw-r--r--test_scripts/src/main/java/com/android/webview/tests/WebviewAppLaunchTest.java290
-rw-r--r--test_targets/webview-app-launch/Android.bp22
-rw-r--r--test_targets/webview-app-launch/OWNERS2
-rw-r--r--test_targets/webview-app-launch/default.xml28
5 files changed, 344 insertions, 0 deletions
diff --git a/test_scripts/src/main/java/com/android/webview/OWNERS b/test_scripts/src/main/java/com/android/webview/OWNERS
new file mode 100644
index 0000000..af3a7c8
--- /dev/null
+++ b/test_scripts/src/main/java/com/android/webview/OWNERS
@@ -0,0 +1,2 @@
+amitku@google.com
+rmhasan@google.com \ No newline at end of file
diff --git a/test_scripts/src/main/java/com/android/webview/tests/WebviewAppLaunchTest.java b/test_scripts/src/main/java/com/android/webview/tests/WebviewAppLaunchTest.java
new file mode 100644
index 0000000..4dac95f
--- /dev/null
+++ b/test_scripts/src/main/java/com/android/webview/tests/WebviewAppLaunchTest.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2022 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.webview.tests;
+
+import com.android.csuite.core.ApkInstaller;
+import com.android.csuite.core.ApkInstaller.ApkInstallerException;
+import com.android.csuite.core.DeviceUtils;
+import com.android.csuite.core.DeviceUtils.DeviceTimestamp;
+import com.android.csuite.core.DeviceUtils.DeviceUtilsException;
+import com.android.csuite.core.TestUtils;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.util.AaptParser;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.RunUtil;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** A test that verifies that a single app can be successfully launched. */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class WebviewAppLaunchTest extends BaseHostJUnit4Test {
+ @Rule public TestLogData mLogData = new TestLogData();
+ private ApkInstaller mApkInstaller;
+ private List<File> mOrderedWebviewApks = new ArrayList<>();
+
+ @Option(name = "record-screen", description = "Whether to record screen during test.")
+ private boolean mRecordScreen;
+
+ @Option(name = "package-name", description = "Package name of testing app.")
+ private String mPackageName;
+
+ @Option(
+ name = "install-apk",
+ description =
+ "The path to an apk file or a directory of apk files of a singe package to be"
+ + " installed on device. Can be repeated.")
+ private List<File> mApkPaths = new ArrayList<>();
+
+ @Option(
+ name = "install-arg",
+ description = "Arguments for the 'adb install-multiple' package installation command.")
+ private final List<String> mInstallArgs = new ArrayList<>();
+
+ @Option(
+ name = "app-launch-timeout-ms",
+ description = "Time to wait for an app to launch in msecs.")
+ private int mAppLaunchTimeoutMs = 20000;
+
+ @Option(
+ name = "webview-apk-dir",
+ description = "The path to the webview apk.",
+ importance = Importance.ALWAYS)
+ private File mWebviewApkDir;
+
+ @Before
+ public void setUp() throws DeviceNotAvailableException, ApkInstallerException, IOException {
+ Assert.assertNotNull("Package name cannot be null", mPackageName);
+
+ readWebviewApkDirectory();
+
+ mApkInstaller = ApkInstaller.getInstance(getDevice());
+ for (File apkPath : mApkPaths) {
+ CLog.d("Installing " + apkPath);
+ mApkInstaller.install(
+ apkPath.toPath(), mInstallArgs.toArray(new String[mInstallArgs.size()]));
+ }
+
+ DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
+ deviceUtils.freezeRotation();
+
+ printWebviewVersion();
+ }
+
+ @Test
+ public void testAppLaunch()
+ throws DeviceNotAvailableException, ApkInstallerException, IOException {
+ AssertionError lastError = null;
+
+ // Try the latest webview version
+ installWebview(mOrderedWebviewApks.get(0));
+ try {
+ assertAppLaunchNoCrash();
+ } catch (AssertionError e) {
+ lastError = e;
+ }
+
+ // If the app doesn't crash, complete the test.
+ if (lastError == null) {
+ return;
+ }
+
+ // If the app crashes, try the app with the original webview version that comes with the
+ // device.
+ uninstallWebview();
+ try {
+ assertAppLaunchNoCrash();
+ } catch (AssertionError newError) {
+ CLog.w(
+ "The app %s crashed both with and without the webview installation,"
+ + " ignoring the failure...",
+ mPackageName);
+ return;
+ }
+
+ for (int idx = 1; idx < mOrderedWebviewApks.size(); idx++) {
+ uninstallWebview();
+ installWebview(mOrderedWebviewApks.get(idx));
+ try {
+ assertAppLaunchNoCrash();
+ } catch (AssertionError e) {
+ lastError = e;
+ continue;
+ }
+ break;
+ }
+
+ throw new AssertionError(
+ String.format(
+ "Package %s crashed since webview version %s",
+ mPackageName, getCurrentWebviewPackage().getVersion()),
+ lastError);
+ }
+
+ @After
+ public void tearDown() throws DeviceNotAvailableException, ApkInstallerException {
+ TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
+ testUtils.collectScreenshot(mPackageName);
+
+ DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
+ deviceUtils.stopPackage(mPackageName);
+ deviceUtils.unfreezeRotation();
+
+ mApkInstaller.uninstallAllInstalledPackages();
+
+ uninstallWebview();
+ printWebviewVersion();
+ }
+
+ private void readWebviewApkDirectory() {
+ mOrderedWebviewApks = Arrays.asList(mWebviewApkDir.listFiles());
+ Collections.sort(
+ mOrderedWebviewApks,
+ new Comparator<File>() {
+ @Override
+ public int compare(File apk1, File apk2) {
+ return getVersionCode(apk2).compareTo(getVersionCode(apk1));
+ }
+
+ private Long getVersionCode(File apk) {
+ return Long.parseLong(AaptParser.parse(apk).getVersionCode());
+ }
+ });
+ }
+
+ private void printWebviewVersion() throws DeviceNotAvailableException {
+ WebviewPackage impl = getCurrentWebviewPackage();
+ CLog.i("Current webview implementation: %s", impl.getPackageName());
+ CLog.i("Current webview version: %s", impl.getVersion());
+ }
+
+ private void installWebview(File apk)
+ throws ApkInstallerException, IOException, DeviceNotAvailableException {
+ ApkInstaller.getInstance(getDevice()).install(apk.toPath());
+ CommandResult res =
+ getDevice()
+ .executeShellV2Command(
+ "cmd webviewupdate set-webview-implementation com.android.webview");
+ Assert.assertEquals(
+ "Failed to set webview update: " + res, res.getStatus(), CommandStatus.SUCCESS);
+ printWebviewVersion();
+ }
+
+ private void uninstallWebview() throws DeviceNotAvailableException {
+ getDevice()
+ .executeShellCommand(
+ "cmd webviewupdate set-webview-implementation com.google.android.webview");
+ getDevice().executeAdbCommand("uninstall com.android.webview");
+ }
+
+ private WebviewPackage getCurrentWebviewPackage() throws DeviceNotAvailableException {
+ String dumpsys = getDevice().executeShellCommand("dumpsys webviewupdate");
+ return WebviewPackage.parseFrom(dumpsys);
+ }
+
+ private static class WebviewPackage {
+ private final String mPackageName;
+ private final String mVersion;
+
+ private WebviewPackage(String packageName, String version) {
+ mPackageName = packageName;
+ mVersion = version;
+ }
+
+ static WebviewPackage parseFrom(String dumpsys) {
+ Pattern pattern =
+ Pattern.compile("Current WebView package \\(name, version\\): \\((.*?)\\)");
+ Matcher matcher = pattern.matcher(dumpsys);
+ Assert.assertTrue("Cannot parse webview package info from: " + dumpsys, matcher.find());
+ String[] packageInfo = matcher.group(1).split(",");
+ return new WebviewPackage(packageInfo[0].strip(), packageInfo[1].strip());
+ }
+
+ String getPackageName() {
+ return mPackageName;
+ }
+
+ String getVersion() {
+ return mVersion;
+ }
+ }
+
+ private void assertAppLaunchNoCrash() throws DeviceNotAvailableException {
+ DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
+ deviceUtils.resetPackage(mPackageName);
+ TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
+
+ if (mRecordScreen) {
+ testUtils.collectScreenRecord(
+ () -> {
+ launchPackageAndCheckForCrash();
+ },
+ mPackageName);
+ } else {
+ launchPackageAndCheckForCrash();
+ }
+ }
+
+ private void launchPackageAndCheckForCrash() throws DeviceNotAvailableException {
+ CLog.d("Launching package: %s.", mPackageName);
+
+ DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
+ TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
+
+ DeviceTimestamp startTime = deviceUtils.currentTimeMillis();
+ try {
+ deviceUtils.launchPackage(mPackageName);
+ } catch (DeviceUtilsException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ CLog.d("Waiting %s milliseconds for the app to launch fully.", mAppLaunchTimeoutMs);
+ RunUtil.getDefault().sleep(mAppLaunchTimeoutMs);
+
+ CLog.d("Completed launching package: %s", mPackageName);
+
+ try {
+ String crashLog = testUtils.getDropboxPackageCrashLog(mPackageName, startTime, true);
+ if (crashLog != null) {
+ Assert.fail(crashLog);
+ }
+ } catch (IOException e) {
+ Assert.fail("Error while getting dropbox crash log: " + e);
+ }
+ }
+}
diff --git a/test_targets/webview-app-launch/Android.bp b/test_targets/webview-app-launch/Android.bp
new file mode 100644
index 0000000..3658018
--- /dev/null
+++ b/test_targets/webview-app-launch/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+csuite_test {
+ name: "webview-app-launch",
+ test_config_template: "default.xml",
+}
diff --git a/test_targets/webview-app-launch/OWNERS b/test_targets/webview-app-launch/OWNERS
new file mode 100644
index 0000000..af3a7c8
--- /dev/null
+++ b/test_targets/webview-app-launch/OWNERS
@@ -0,0 +1,2 @@
+amitku@google.com
+rmhasan@google.com \ No newline at end of file
diff --git a/test_targets/webview-app-launch/default.xml b/test_targets/webview-app-launch/default.xml
new file mode 100644
index 0000000..0b5470b
--- /dev/null
+++ b/test_targets/webview-app-launch/default.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<configuration description="Launches an app and check for crashes">
+ <target_preparer class="com.android.compatibility.targetprep.CheckGmsPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP"/>
+ <option name="run-command" value="input keyevent KEYCODE_MENU"/>
+ <option name="run-command" value="input keyevent KEYCODE_HOME"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="set-option" value="package-name:{package}"/>
+ <option name="set-option" value="install-apk:app\://{package}"/>
+ <option name="class" value="com.android.webview.tests.WebviewAppLaunchTest" />
+ </test>
+</configuration> \ No newline at end of file