1 /*
2  * Copyright (C) 2023 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.tradefed.config.Option;
20 import com.android.tradefed.config.Option.Importance;
21 import com.android.tradefed.invoker.TestInformation;
22 import com.android.tradefed.targetprep.ITargetPreparer;
23 import com.android.tradefed.targetprep.TargetSetupError;
24 import com.android.tradefed.util.CommandResult;
25 import com.android.tradefed.util.CommandStatus;
26 import com.android.tradefed.util.RunUtil;
27 
28 import org.junit.Assert;
29 
30 import java.io.File;
31 import java.nio.file.Files;
32 import java.nio.file.Paths;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 
37 import javax.annotation.Nullable;
38 
39 public class WebviewInstallerToolPreparer implements ITargetPreparer {
40     private static final long COMMAND_TIMEOUT_MILLIS = 5 * 60 * 1000;
41     private static final String WEBVIEW_INSTALLER_TOOL_PATH = "WEBVIEW_INSTALLER_TOOL_PATH";
42     private static final String GCLOUD_CLI_PATH = "GCLOUD_CLI_PATH";
43 
44     private File mGcloudCliDir;
45     private RunUtilProvider mRunUtilProvider;
46 
47     @Option(
48             name = "gcloud-cli-zip-archive",
49             description = "Path to the google cli zip archive.",
50             importance = Importance.ALWAYS)
51     private File mGcloudCliZipArchive;
52 
53     @Option(
54             name = "webview-installer-tool",
55             description = "Path to the webview installer executable.",
56             importance = Importance.ALWAYS)
57     private File mWebviewInstallerTool;
58 
WebviewInstallerToolPreparer(RunUtilProvider runUtilProvider)59     public WebviewInstallerToolPreparer(RunUtilProvider runUtilProvider) {
60         mRunUtilProvider = runUtilProvider;
61     }
62 
WebviewInstallerToolPreparer()63     public WebviewInstallerToolPreparer() {
64         this(() -> new RunUtil());
65     }
66 
runWebviewInstallerToolCommand( TestInformation testInformation, @Nullable String webviewVersion, @Nullable String releaseChannel, List<String> extraArgs)67     public static CommandResult runWebviewInstallerToolCommand(
68             TestInformation testInformation,
69             @Nullable String webviewVersion,
70             @Nullable String releaseChannel,
71             List<String> extraArgs) {
72         RunUtil runUtil = new RunUtil();
73         runUtil.setEnvVariable("HOME", getGcloudCliPath(testInformation));
74 
75         List<String> commandLineArgs =
76                 new ArrayList<>(
77                         Arrays.asList(
78                                 getWebviewInstallerToolPath(testInformation),
79                                 "--non-next",
80                                 "--serial",
81                                 testInformation.getDevice().getSerialNumber(),
82                                 "-vvv",
83                                 "--gsutil",
84                                 Paths.get(
85                                                 getGcloudCliPath(testInformation),
86                                                 "google-cloud-sdk",
87                                                 "bin",
88                                                 "gsutil")
89                                         .toFile()
90                                         .getAbsolutePath()));
91         commandLineArgs.addAll(extraArgs);
92 
93         if (webviewVersion != null) {
94             commandLineArgs.addAll(Arrays.asList("--chrome-version", webviewVersion));
95         }
96 
97         if (releaseChannel != null) {
98             commandLineArgs.addAll(Arrays.asList("--channel", releaseChannel));
99         }
100 
101         return runUtil.runTimedCmd(
102                 COMMAND_TIMEOUT_MILLIS,
103                 System.out,
104                 System.out,
105                 commandLineArgs.toArray(new String[0]));
106     }
107 
setGcloudCliPath(TestInformation testInformation, File gcloudCliDir)108     public static void setGcloudCliPath(TestInformation testInformation, File gcloudCliDir) {
109         testInformation
110                 .getBuildInfo()
111                 .addBuildAttribute(GCLOUD_CLI_PATH, gcloudCliDir.getAbsolutePath());
112     }
113 
setWebviewInstallerToolPath( TestInformation testInformation, File webviewInstallerTool)114     public static void setWebviewInstallerToolPath(
115             TestInformation testInformation, File webviewInstallerTool) {
116         testInformation
117                 .getBuildInfo()
118                 .addBuildAttribute(
119                         WEBVIEW_INSTALLER_TOOL_PATH, webviewInstallerTool.getAbsolutePath());
120     }
121 
getWebviewInstallerToolPath(TestInformation testInformation)122     public static String getWebviewInstallerToolPath(TestInformation testInformation) {
123         return testInformation.getBuildInfo().getBuildAttributes().get(WEBVIEW_INSTALLER_TOOL_PATH);
124     }
125 
getGcloudCliPath(TestInformation testInformation)126     public static String getGcloudCliPath(TestInformation testInformation) {
127         return testInformation.getBuildInfo().getBuildAttributes().get(GCLOUD_CLI_PATH);
128     }
129 
130     @Override
setUp(TestInformation testInfo)131     public void setUp(TestInformation testInfo) throws TargetSetupError {
132         Assert.assertNotEquals(
133                 "Argument --webview-installer-tool must be used.", mWebviewInstallerTool, null);
134         Assert.assertNotEquals(
135                 "Argument --gcloud-cli-zip must be used.", mGcloudCliZipArchive, null);
136         try {
137             RunUtil runUtil = mRunUtilProvider.get();
138             mGcloudCliDir = Files.createTempDirectory(null).toFile();
139             CommandResult unzipRes =
140                     runUtil.runTimedCmd(
141                             COMMAND_TIMEOUT_MILLIS,
142                             "unzip",
143                             mGcloudCliZipArchive.getAbsolutePath(),
144                             "-d",
145                             mGcloudCliDir.getAbsolutePath());
146 
147             Assert.assertEquals(
148                     "Unable to unzip the gcloud cli zip archive",
149                     unzipRes.getStatus(),
150                     CommandStatus.SUCCESS);
151 
152             // The 'gcloud init' command creates configuration files for gsutil and other
153             // applications that use the gcloud sdk in the home directory. We can isolate
154             // the effects of these configuration files to the processes that run the
155             // gcloud and gsutil executables tracked by this class by setting the home
156             // directory for processes that run those executables to a temporary directory
157             // also tracked by this class.
158             runUtil.setEnvVariable("HOME", mGcloudCliDir.getAbsolutePath());
159             File gcloudBin =
160                     mGcloudCliDir
161                             .toPath()
162                             .resolve(Paths.get("google-cloud-sdk", "bin", "gcloud"))
163                             .toFile();
164             String gcloudInitScript =
165                     String.format(
166                             "printf \"1\\n1\" | %s init --console-only",
167                             gcloudBin.getAbsolutePath());
168             CommandResult gcloudInitRes =
169                     runUtil.runTimedCmd(
170                             COMMAND_TIMEOUT_MILLIS,
171                             System.out,
172                             System.out,
173                             "sh",
174                             "-c",
175                             gcloudInitScript);
176             Assert.assertEquals(
177                     "gcloud cli initialization failed",
178                     gcloudInitRes.getStatus(),
179                     CommandStatus.SUCCESS);
180 
181             CommandResult chmodRes =
182                     runUtil.runTimedCmd(
183                             COMMAND_TIMEOUT_MILLIS,
184                             System.out,
185                             System.out,
186                             "chmod",
187                             "755",
188                             "-v",
189                             mWebviewInstallerTool.getAbsolutePath());
190 
191             Assert.assertEquals(
192                     "The 'chmod 755 -v <WebView installer tool>' command failed",
193                     chmodRes.getStatus(),
194                     CommandStatus.SUCCESS);
195 
196         } catch (Exception ex) {
197             throw new TargetSetupError("Caught an exception during setup:\n" + ex);
198         }
199         setGcloudCliPath(testInfo, mGcloudCliDir);
200         setWebviewInstallerToolPath(testInfo, mWebviewInstallerTool);
201     }
202 
203     @Override
tearDown(TestInformation testInfo, Throwable e)204     public void tearDown(TestInformation testInfo, Throwable e) {
205         // Clean up some files.
206         mRunUtilProvider
207                 .get()
208                 .runTimedCmd(COMMAND_TIMEOUT_MILLIS, "rm", "-rf", mGcloudCliDir.getAbsolutePath());
209     }
210 
211     interface RunUtilProvider {
get()212         RunUtil get();
213     }
214 }
215