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