1 /* 2 * Copyright (C) 2019 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 package com.android.tradefed.invoker; 17 18 import com.android.tradefed.build.IBuildInfo; 19 import com.android.tradefed.device.ITestDevice; 20 import com.android.tradefed.invoker.ExecutionFiles.FilesKey; 21 import com.android.tradefed.util.FileUtil; 22 23 import java.io.File; 24 import java.io.FileNotFoundException; 25 import java.util.List; 26 27 /** 28 * Holder object that contains all the information and dependencies a test runner or test might need 29 * to execute properly. 30 */ 31 public class TestInformation { 32 /** The context of the invocation or module in progress */ 33 private final IInvocationContext mContext; 34 /** Properties generated during execution. */ 35 private final ExecutionProperties mProperties; 36 /** 37 * Files generated during execution that needs to be carried, they will be deleted at the end of 38 * the invocation. 39 */ 40 private final ExecutionFiles mExecutionFiles; 41 42 /** Main folder for all dependencies of tests */ 43 private final File mDependenciesFolder; 44 45 private int mPrimaryDeviceIndex = 0; 46 TestInformation(Builder builder)47 private TestInformation(Builder builder) { 48 mContext = builder.mContext; 49 mProperties = builder.mProperties; 50 mDependenciesFolder = builder.mDependenciesFolder; 51 mExecutionFiles = builder.mExecutionFiles; 52 } 53 TestInformation( TestInformation invocationInfo, IInvocationContext moduleContext, boolean copyExecFile)54 private TestInformation( 55 TestInformation invocationInfo, 56 IInvocationContext moduleContext, 57 boolean copyExecFile) { 58 mContext = moduleContext; 59 mProperties = invocationInfo.mProperties; 60 mDependenciesFolder = invocationInfo.mDependenciesFolder; 61 if (copyExecFile) { 62 mExecutionFiles = new ExecutionFiles(); 63 mExecutionFiles.putAll(invocationInfo.executionFiles()); 64 } else { 65 mExecutionFiles = invocationInfo.mExecutionFiles; 66 } 67 } 68 69 /** Create a builder for creating {@link TestInformation} instances. */ newBuilder()70 public static Builder newBuilder() { 71 return new Builder(); 72 } 73 74 /** Create an {@link TestInformation} representing a module rather than an invocation. */ createModuleTestInfo( TestInformation invocationInfo, IInvocationContext moduleContext)75 public static TestInformation createModuleTestInfo( 76 TestInformation invocationInfo, IInvocationContext moduleContext) { 77 return new TestInformation(invocationInfo, moduleContext, false); 78 } 79 80 /** Create an {@link TestInformation} with a copied {@link ExecutionFiles}. */ createCopyTestInfo( TestInformation invocationInfo, IInvocationContext context)81 public static TestInformation createCopyTestInfo( 82 TestInformation invocationInfo, IInvocationContext context) { 83 return new TestInformation(invocationInfo, context, true); 84 } 85 86 /** Returns the current invocation context, or the module context if this is a module. */ getContext()87 public IInvocationContext getContext() { 88 return mContext; 89 } 90 91 /** Returns the primary device under tests. */ getDevice()92 public ITestDevice getDevice() { 93 return mContext.getDevices().get(mPrimaryDeviceIndex); 94 } 95 96 /** Returns the list of devices part of the invocation. */ getDevices()97 public List<ITestDevice> getDevices() { 98 return mContext.getDevices(); 99 } 100 101 /** Returns the primary device build information. */ getBuildInfo()102 public IBuildInfo getBuildInfo() { 103 return mContext.getBuildInfos().get(mPrimaryDeviceIndex); 104 } 105 106 /** 107 * Test Harness internal method to switch which device is returned by default with {@link 108 * #getDevice()}. Always reset to 0. 109 */ setActiveDeviceIndex(int index)110 public final void setActiveDeviceIndex(int index) { 111 mPrimaryDeviceIndex = index; 112 } 113 114 /** 115 * Returns the properties generated during the invocation execution. Passing values and 116 * information through the {@link ExecutionProperties} is the recommended way to exchange 117 * information between target_preparers and tests. 118 */ properties()119 public ExecutionProperties properties() { 120 return mProperties; 121 } 122 123 /** 124 * Returns the files generated during the invocation execution. Passing files through the {@link 125 * ExecutionFiles} is the recommended way to make a file available between target_preparers and 126 * tests. 127 */ executionFiles()128 public ExecutionFiles executionFiles() { 129 return mExecutionFiles; 130 } 131 132 /** Returns the folder where all the dependencies are stored for an invocation. */ dependenciesFolder()133 public File dependenciesFolder() { 134 return mDependenciesFolder; 135 } 136 137 /** Builder to create a {@link TestInformation} instance. */ 138 public static class Builder { 139 private IInvocationContext mContext; 140 private ExecutionProperties mProperties; 141 private File mDependenciesFolder; 142 private ExecutionFiles mExecutionFiles; 143 Builder()144 private Builder() { 145 mProperties = new ExecutionProperties(); 146 mExecutionFiles = new ExecutionFiles(); 147 } 148 build()149 public TestInformation build() { 150 return new TestInformation(this); 151 } 152 setInvocationContext(IInvocationContext context)153 public Builder setInvocationContext(IInvocationContext context) { 154 this.mContext = context; 155 return this; 156 } 157 setDependenciesFolder(File dependenciesFolder)158 public Builder setDependenciesFolder(File dependenciesFolder) { 159 this.mDependenciesFolder = dependenciesFolder; 160 return this; 161 } 162 } 163 164 /** 165 * Search for a dependency/artifact file based on its name, and whether or not it's a target or 166 * host file (for quicker search). 167 * 168 * @param fileName The name of the file we are looking for. 169 * @param targetFirst whether or not we are favoring target-side files vs. host-side files for 170 * the search. 171 * @return The found artifact file. 172 * @throws FileNotFoundException If the file is not found. 173 */ getDependencyFile(String fileName, boolean targetFirst)174 public File getDependencyFile(String fileName, boolean targetFirst) 175 throws FileNotFoundException { 176 File dependency = null; 177 dependency = getFromEnv(fileName, targetFirst); 178 if (dependency != null && dependency.isFile()) { 179 return dependency; 180 } 181 dependency = getFromTestsDir(fileName); 182 if (dependency != null && dependency.isFile()) { 183 return dependency; 184 } 185 dependency = getFile(fileName); 186 if (dependency != null && dependency.isFile()) { 187 return dependency; 188 } 189 dependency = getFromDependencyFolder(fileName); 190 if (dependency != null && dependency.isFile()) { 191 return dependency; 192 } 193 throw new FileNotFoundException( 194 String.format("Could not find an artifact file associated with %s", fileName)); 195 } 196 getFromEnv(String fileName, boolean targetFirst)197 private File getFromEnv(String fileName, boolean targetFirst) { 198 FilesKey hostOrTarget = FilesKey.HOST_TESTS_DIRECTORY; 199 if (targetFirst) { 200 hostOrTarget = FilesKey.TARGET_TESTS_DIRECTORY; 201 } 202 File testsDir = mExecutionFiles.get(hostOrTarget); 203 if (testsDir != null && testsDir.exists()) { 204 File file = FileUtil.findFile(testsDir, fileName); 205 if (file != null) { 206 return file; 207 } 208 } 209 return null; 210 } 211 getFromTestsDir(String fileName)212 private File getFromTestsDir(String fileName) { 213 File testsDir = mExecutionFiles.get(FilesKey.TESTS_DIRECTORY); 214 if (testsDir != null && testsDir.exists()) { 215 File file = FileUtil.findFile(testsDir, fileName); 216 if (file == null) { 217 // TODO(b/138416078): Once build dependency can be fixed and test required 218 // APKs are all under the test module directory, we can remove this fallback 219 // approach to do individual download from remote artifact. 220 // Try to stage the files from remote zip files. 221 file = getBuildInfo().stageRemoteFile(fileName, testsDir); 222 } 223 return file; 224 } 225 return null; 226 } 227 getFile(String fileName)228 private File getFile(String fileName) { 229 return mExecutionFiles.get(fileName); 230 } 231 getFromDependencyFolder(String fileName)232 private File getFromDependencyFolder(String fileName) { 233 File testsDir = mDependenciesFolder; 234 if (testsDir != null && testsDir.exists()) { 235 File file = FileUtil.findFile(testsDir, fileName); 236 if (file != null) { 237 return file; 238 } 239 } 240 return null; 241 } 242 } 243