• 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.testtype.binary;
17 
18 import com.android.tradefed.config.Option;
19 import com.android.tradefed.config.OptionCopier;
20 import com.android.tradefed.device.DeviceNotAvailableException;
21 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
22 import com.android.tradefed.result.ITestInvocationListener;
23 import com.android.tradefed.result.TestDescription;
24 import com.android.tradefed.testtype.IAbi;
25 import com.android.tradefed.testtype.IAbiReceiver;
26 import com.android.tradefed.testtype.IRemoteTest;
27 import com.android.tradefed.testtype.IRuntimeHintProvider;
28 import com.android.tradefed.testtype.IShardableTest;
29 import com.android.tradefed.testtype.ITestCollector;
30 
31 import java.io.File;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.HashMap;
35 import java.util.List;
36 
37 /** Base class for executable style of tests. For example: binaries, shell scripts. */
38 public abstract class ExecutableBaseTest
39         implements IRemoteTest, IRuntimeHintProvider, ITestCollector, IShardableTest, IAbiReceiver {
40 
41     public static final String NO_BINARY_ERROR = "Binary %s does not exist.";
42 
43     @Option(name = "binary", description = "Path to the binary to be run. Can be repeated.")
44     private List<String> mBinaryPaths = new ArrayList<>();
45 
46     @Option(
47         name = "collect-tests-only",
48         description = "Only dry-run through the tests, do not actually run them."
49     )
50     private boolean mCollectTestsOnly = false;
51 
52     @Option(
53         name = "runtime-hint",
54         description = "The hint about the test's runtime.",
55         isTimeVal = true
56     )
57     private long mRuntimeHintMs = 60000L; // 1 minute
58 
59     private IAbi mAbi;
60 
61     @Override
run(ITestInvocationListener listener)62     public final void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
63         for (String binary : mBinaryPaths) {
64             String path = findBinary(binary);
65             if (path == null) {
66                 listener.testRunStarted(new File(binary).getName(), 0);
67                 listener.testRunFailed(String.format(NO_BINARY_ERROR, binary));
68                 listener.testRunEnded(0L, new HashMap<String, Metric>());
69             } else {
70                 listener.testRunStarted(new File(path).getName(), 1);
71                 long startTimeMs = System.currentTimeMillis();
72                 TestDescription description =
73                         new TestDescription(new File(path).getName(), new File(path).getName());
74                 listener.testStarted(description);
75                 try {
76                     if (!mCollectTestsOnly) {
77                         // Do not actually run the test if we are dry running it.
78                         runBinary(path, listener, description);
79                     }
80                 } finally {
81                     listener.testEnded(description, new HashMap<String, Metric>());
82                     listener.testRunEnded(
83                             System.currentTimeMillis() - startTimeMs,
84                             new HashMap<String, Metric>());
85                 }
86             }
87         }
88     }
89 
90     /**
91      * Search for the binary to be able to run it.
92      *
93      * @param binary the path of the binary or simply the binary name.
94      * @return The path to the binary, or null if not found.
95      */
findBinary(String binary)96     public abstract String findBinary(String binary);
97 
98     /**
99      * Actually run the binary at the given path.
100      *
101      * @param binaryPath The path of the binary.
102      * @param listener The listener where to report the results.
103      * @param description The test in progress.
104      */
runBinary( String binaryPath, ITestInvocationListener listener, TestDescription description)105     public abstract void runBinary(
106             String binaryPath, ITestInvocationListener listener, TestDescription description)
107             throws DeviceNotAvailableException;
108 
109     /** {@inheritDoc} */
110     @Override
setCollectTestsOnly(boolean shouldCollectTest)111     public final void setCollectTestsOnly(boolean shouldCollectTest) {
112         mCollectTestsOnly = shouldCollectTest;
113     }
114 
115     /** {@inheritDoc} */
116     @Override
getRuntimeHint()117     public final long getRuntimeHint() {
118         return mRuntimeHintMs;
119     }
120 
121     /** {@inheritDoc} */
122     @Override
setAbi(IAbi abi)123     public final void setAbi(IAbi abi) {
124         mAbi = abi;
125     }
126 
127     /** {@inheritDoc} */
128     @Override
getAbi()129     public IAbi getAbi() {
130         return mAbi;
131     }
132 
133     /** {@inheritDoc} */
134     @Override
split()135     public final Collection<IRemoteTest> split() {
136         if (mBinaryPaths.size() <= 2) {
137             return null;
138         }
139         Collection<IRemoteTest> tests = new ArrayList<>();
140         for (String path : mBinaryPaths) {
141             tests.add(getTestShard(path));
142         }
143         return tests;
144     }
145 
getTestShard(String path)146     private IRemoteTest getTestShard(String path) {
147         ExecutableBaseTest shard = null;
148         try {
149             shard = this.getClass().newInstance();
150             OptionCopier.copyOptionsNoThrow(this, shard);
151             // We approximate the runtime of each shard to be equal since we can't know.
152             shard.mRuntimeHintMs = mRuntimeHintMs / shard.mBinaryPaths.size();
153             // Set one binary per shard
154             shard.mBinaryPaths.clear();
155             shard.mBinaryPaths.add(path);
156         } catch (InstantiationException | IllegalAccessException e) {
157             // This cannot happen because the class was already created once at that point.
158             throw new RuntimeException(
159                     String.format(
160                             "%s (%s) when attempting to create shard object",
161                             e.getClass().getSimpleName(), e.getMessage()));
162         }
163         return shard;
164     }
165 }
166