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