• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.webview.tests;
18 
19 import com.android.csuite.core.ApkInstaller;
20 import com.android.csuite.core.ApkInstaller.ApkInstallerException;
21 import com.android.csuite.core.DeviceUtils;
22 import com.android.csuite.core.DeviceUtils.DeviceTimestamp;
23 import com.android.csuite.core.DeviceUtils.DeviceUtilsException;
24 import com.android.csuite.core.TestUtils;
25 import com.android.tradefed.config.Option;
26 import com.android.tradefed.device.DeviceNotAvailableException;
27 import com.android.tradefed.log.LogUtil.CLog;
28 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
29 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
30 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
31 import com.android.tradefed.util.RunUtil;
32 
33 import org.junit.After;
34 import org.junit.Assert;
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 
40 import java.io.File;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 
46 /** A test that verifies that a single app can be successfully launched. */
47 @RunWith(DeviceJUnit4ClassRunner.class)
48 public class WebviewAppLaunchTest extends BaseHostJUnit4Test {
49     @Rule public TestLogData mLogData = new TestLogData();
50 
51     private static final long COMMAND_TIMEOUT_MILLIS = 5 * 60 * 1000;
52     private WebviewUtils mWebviewUtils;
53     private WebviewPackage mPreInstalledWebview;
54     private ApkInstaller mApkInstaller;
55 
56     @Option(name = "record-screen", description = "Whether to record screen during test.")
57     private boolean mRecordScreen;
58 
59     @Option(name = "webview-version-to-test", description = "Version of Webview to test.")
60     private String mWebviewVersionToTest;
61 
62     @Option(
63             name = "release-channel",
64             description = "Release channel to fetch Webview from, i.e. stable.")
65     private String mReleaseChannel;
66 
67     @Option(name = "package-name", description = "Package name of testing app.")
68     private String mPackageName;
69 
70     @Option(
71             name = "install-apk",
72             description =
73                     "The path to an apk file or a directory of apk files of a singe package to be"
74                             + " installed on device. Can be repeated.")
75     private List<File> mApkPaths = new ArrayList<>();
76 
77     @Option(
78             name = "install-arg",
79             description = "Arguments for the 'adb install-multiple' package installation command.")
80     private final List<String> mInstallArgs = new ArrayList<>();
81 
82     @Option(
83             name = "app-launch-timeout-ms",
84             description = "Time to wait for an app to launch in msecs.")
85     private int mAppLaunchTimeoutMs = 20000;
86 
87     @Before
setUp()88     public void setUp() throws DeviceNotAvailableException, ApkInstallerException, IOException {
89         Assert.assertNotNull("Package name cannot be null", mPackageName);
90         Assert.assertTrue(
91                 "Either the --release-channel or --webview-version-to-test arguments "
92                         + "must be used",
93                 mWebviewVersionToTest != null || mReleaseChannel != null);
94 
95         mApkInstaller = ApkInstaller.getInstance(getDevice());
96         mWebviewUtils = new WebviewUtils(getTestInformation());
97         mPreInstalledWebview = mWebviewUtils.getCurrentWebviewPackage();
98 
99         for (File apkPath : mApkPaths) {
100             CLog.d("Installing " + apkPath);
101             mApkInstaller.install(apkPath.toPath(), mInstallArgs);
102         }
103 
104         DeviceUtils.getInstance(getDevice()).freezeRotation();
105         mWebviewUtils.printWebviewVersion();
106     }
107 
108     @Test
testAppLaunch()109     public void testAppLaunch()
110             throws DeviceNotAvailableException, InterruptedException, ApkInstallerException,
111                     IOException {
112         AssertionError lastError = null;
113         WebviewPackage lastWebviewInstalled =
114                 mWebviewUtils.installWebview(mWebviewVersionToTest, mReleaseChannel);
115 
116         try {
117             assertAppLaunchNoCrash();
118         } catch (AssertionError e) {
119             lastError = e;
120         } finally {
121             mWebviewUtils.uninstallWebview(lastWebviewInstalled, mPreInstalledWebview);
122         }
123 
124         // If the app doesn't crash, complete the test.
125         if (lastError == null) {
126             return;
127         }
128 
129         // If the app crashes, try the app with the original webview version that comes with the
130         // device.
131         try {
132             assertAppLaunchNoCrash();
133         } catch (AssertionError newError) {
134             CLog.w(
135                     "The app %s crashed both with and without the webview installation,"
136                             + " ignoring the failure...",
137                     mPackageName);
138             return;
139         }
140         throw new AssertionError(
141                 String.format(
142                         "Package %s crashed since webview version %s",
143                         mPackageName, lastWebviewInstalled.getVersion()),
144                 lastError);
145     }
146 
147     @After
tearDown()148     public void tearDown() throws DeviceNotAvailableException, ApkInstallerException {
149         TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
150         testUtils.collectScreenshot(mPackageName);
151 
152         DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
153         deviceUtils.stopPackage(mPackageName);
154         deviceUtils.unfreezeRotation();
155 
156         mApkInstaller.uninstallAllInstalledPackages();
157         mWebviewUtils.printWebviewVersion();
158     }
159 
assertAppLaunchNoCrash()160     private void assertAppLaunchNoCrash() throws DeviceNotAvailableException {
161         DeviceUtils.getInstance(getDevice()).resetPackage(mPackageName);
162         TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
163 
164         if (mRecordScreen) {
165             testUtils.collectScreenRecord(
166                     () -> {
167                         launchPackageAndCheckForCrash();
168                     },
169                     mPackageName);
170         } else {
171             launchPackageAndCheckForCrash();
172         }
173     }
174 
launchPackageAndCheckForCrash()175     private void launchPackageAndCheckForCrash() throws DeviceNotAvailableException {
176         CLog.d("Launching package: %s.", mPackageName);
177 
178         TestUtils testUtils = TestUtils.getInstance(getTestInformation(), mLogData);
179         DeviceUtils deviceUtils = DeviceUtils.getInstance(getDevice());
180         DeviceTimestamp startTime = deviceUtils.currentTimeMillis();
181         try {
182             deviceUtils.launchPackage(mPackageName);
183         } catch (DeviceUtilsException e) {
184             Assert.fail(e.getMessage());
185         }
186 
187         CLog.d("Waiting %s milliseconds for the app to launch fully.", mAppLaunchTimeoutMs);
188         RunUtil.getDefault().sleep(mAppLaunchTimeoutMs);
189 
190         CLog.d("Completed launching package: %s", mPackageName);
191 
192         try {
193             String crashLog = testUtils.getDropboxPackageCrashLog(mPackageName, startTime, true);
194             if (crashLog != null) {
195                 Assert.fail(crashLog);
196             }
197         } catch (IOException e) {
198             Assert.fail("Error while getting dropbox crash log: " + e);
199         }
200     }
201 }
202