1 /* 2 * Copyright (C) 2021 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.csuite.core; 18 19 import com.android.tradefed.config.Option; 20 import com.android.tradefed.invoker.TestInformation; 21 import com.android.tradefed.log.LogUtil.CLog; 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.IRunUtil; 27 import com.android.tradefed.util.RunUtil; 28 29 import com.google.common.annotations.VisibleForTesting; 30 import com.google.common.io.MoreFiles; 31 32 import java.io.File; 33 import java.io.IOException; 34 import java.nio.file.FileSystem; 35 import java.nio.file.FileSystems; 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 39 /** A Tradefed preparer that preparers an app crawler on the host before testing. */ 40 public final class AppCrawlTesterHostPreparer implements ITargetPreparer { 41 private static final long COMMAND_TIMEOUT_MILLIS = 4 * 60 * 1000; 42 private static final String SDK_PATH_KEY = "SDK_PATH_KEY"; 43 private static final String CRAWLER_BIN_PATH_KEY = "CSUITE_INTERNAL_CRAWLER_BIN_PATH"; 44 private static final String CREDENTIAL_PATH_KEY = "CSUITE_INTERNAL_CREDENTIAL_PATH"; 45 private static final String IS_READY_KEY = "CSUITE_INTERNAL_IS_READY"; 46 @VisibleForTesting static final String SDK_TAR_OPTION = "sdk-tar"; 47 @VisibleForTesting static final String CRAWLER_BIN_OPTION = "crawler-bin"; 48 @VisibleForTesting static final String CREDENTIAL_JSON_OPTION = "credential-json"; 49 private final FileSystem mFileSystem; 50 51 @Option( 52 name = SDK_TAR_OPTION, 53 mandatory = true, 54 description = "The path to a tar file that contains the Android SDK.") 55 private File mSdkTar; 56 57 @Option( 58 name = CRAWLER_BIN_OPTION, 59 mandatory = true, 60 description = "Path to the directory containing the required crawler binary files.") 61 private File mCrawlerBin; 62 63 @Option( 64 name = CREDENTIAL_JSON_OPTION, 65 mandatory = true, 66 description = "The credential json file to access the crawler server.") 67 private File mCredential; 68 69 private RunUtilProvider mRunUtilProvider; 70 AppCrawlTesterHostPreparer()71 public AppCrawlTesterHostPreparer() { 72 this(() -> new RunUtil(), FileSystems.getDefault()); 73 } 74 75 @VisibleForTesting AppCrawlTesterHostPreparer(RunUtilProvider runUtilProvider, FileSystem fileSystem)76 AppCrawlTesterHostPreparer(RunUtilProvider runUtilProvider, FileSystem fileSystem) { 77 mRunUtilProvider = runUtilProvider; 78 mFileSystem = fileSystem; 79 } 80 81 /** 82 * Returns a path that contains Android SDK. 83 * 84 * @param testInfo The test info where the path is stored in. 85 * @return The path to Android SDK; Null if not set. 86 */ getSdkPath(TestInformation testInfo)87 public static String getSdkPath(TestInformation testInfo) { 88 return getPathFromBuildInfo(testInfo, SDK_PATH_KEY); 89 } 90 91 /** 92 * Returns a path that contains the crawler binaries. 93 * 94 * @param testInfo The test info where the path is stored in. 95 * @return The path to the crawler binaries folder; Null if not set. 96 */ getCrawlerBinPath(TestInformation testInfo)97 public static String getCrawlerBinPath(TestInformation testInfo) { 98 return getPathFromBuildInfo(testInfo, CRAWLER_BIN_PATH_KEY); 99 } 100 101 /** 102 * Returns a path to the credential json file for accessing the Robo crawler server. 103 * 104 * @param testInfo The test info where the path is stored in. 105 * @return The path to the crawler credential json file. 106 */ getCredentialPath(TestInformation testInfo)107 public static String getCredentialPath(TestInformation testInfo) { 108 return getPathFromBuildInfo(testInfo, CREDENTIAL_PATH_KEY); 109 } 110 111 /** 112 * Checks whether the preparer has successfully executed. 113 * 114 * @param testInfo The test info . 115 * @return True if the preparer was executed successfully; False otherwise. 116 */ isReady(TestInformation testInfo)117 public static boolean isReady(TestInformation testInfo) { 118 return testInfo.getBuildInfo().getBuildAttributes().get(IS_READY_KEY) != null; 119 } 120 getPathFromBuildInfo(TestInformation testInfo, String key)121 private static String getPathFromBuildInfo(TestInformation testInfo, String key) { 122 return testInfo.getBuildInfo().getBuildAttributes().get(key); 123 } 124 125 @VisibleForTesting setSdkPath(TestInformation testInfo, Path path)126 static void setSdkPath(TestInformation testInfo, Path path) { 127 testInfo.getBuildInfo().addBuildAttribute(SDK_PATH_KEY, path.toString()); 128 } 129 130 @VisibleForTesting setCrawlerBinPath(TestInformation testInfo, Path path)131 static void setCrawlerBinPath(TestInformation testInfo, Path path) { 132 testInfo.getBuildInfo().addBuildAttribute(CRAWLER_BIN_PATH_KEY, path.toString()); 133 } 134 135 @VisibleForTesting setCredentialPath(TestInformation testInfo, Path path)136 static void setCredentialPath(TestInformation testInfo, Path path) { 137 testInfo.getBuildInfo().addBuildAttribute(CREDENTIAL_PATH_KEY, path.toString()); 138 } 139 140 @Override setUp(TestInformation testInfo)141 public void setUp(TestInformation testInfo) throws TargetSetupError { 142 IRunUtil runUtil = mRunUtilProvider.get(); 143 144 Path sdkPath; 145 try { 146 sdkPath = Files.createTempDirectory("android-sdk"); 147 } catch (IOException e) { 148 throw new TargetSetupError("Failed to create the output path for android sdk.", e); 149 } 150 151 String cmd = "tar -xvzf " + mSdkTar.getPath() + " -C " + sdkPath.toString(); 152 CLog.i("Decompressing Android SDK to " + sdkPath.toString()); 153 CommandResult res = runUtil.runTimedCmd(COMMAND_TIMEOUT_MILLIS, cmd.split(" ")); 154 if (!res.getStatus().equals(CommandStatus.SUCCESS)) { 155 throw new TargetSetupError(String.format("Failed to untar android sdk: %s", res)); 156 } 157 158 setSdkPath(testInfo, sdkPath); 159 160 Path jar = mCrawlerBin.toPath().resolve("crawl_launcher_deploy.jar"); 161 if (!Files.exists(jar)) { 162 jar = mCrawlerBin.toPath().resolve("utp-cli-android_deploy.jar"); 163 } 164 165 // Make the crawler binary executable. 166 String chmodCmd = "chmod 555 " + jar.toString(); 167 CommandResult chmodRes = runUtil.runTimedCmd(COMMAND_TIMEOUT_MILLIS, chmodCmd.split(" ")); 168 if (!chmodRes.getStatus().equals(CommandStatus.SUCCESS)) { 169 throw new TargetSetupError( 170 String.format("Failed to make crawler binary executable: %s", chmodRes)); 171 } 172 173 setCrawlerBinPath(testInfo, mCrawlerBin.toPath()); 174 175 setCredentialPath(testInfo, mCredential.toPath()); 176 177 testInfo.getBuildInfo().addBuildAttribute(IS_READY_KEY, "true"); 178 } 179 180 @Override tearDown(TestInformation testInfo, Throwable e)181 public void tearDown(TestInformation testInfo, Throwable e) { 182 try { 183 cleanUp(mFileSystem.getPath(getSdkPath(testInfo))); 184 } catch (IOException ioException) { 185 CLog.e(ioException); 186 } 187 } 188 cleanUp(Path path)189 private static void cleanUp(Path path) throws IOException { 190 if (path == null || !Files.exists(path)) { 191 return; 192 } 193 194 MoreFiles.deleteRecursively(path); 195 } 196 197 @VisibleForTesting 198 interface RunUtilProvider { get()199 IRunUtil get(); 200 } 201 } 202