1 /*
2  * Copyright (C) 2015 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.compatibility.common.tradefed.testtype;
17 
18 import com.android.compatibility.common.tradefed.result.IModuleListener;
19 import com.android.compatibility.common.tradefed.result.ModuleListener;
20 import com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher;
21 import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
22 import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
23 import com.android.tradefed.build.IBuildInfo;
24 import com.android.tradefed.config.ConfigurationDescriptor;
25 import com.android.tradefed.config.ConfigurationException;
26 import com.android.tradefed.config.OptionSetter;
27 import com.android.tradefed.device.DeviceNotAvailableException;
28 import com.android.tradefed.device.ITestDevice;
29 import com.android.tradefed.invoker.IInvocationContext;
30 import com.android.tradefed.log.LogUtil.CLog;
31 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
32 import com.android.tradefed.result.ITestInvocationListener;
33 import com.android.tradefed.result.ResultForwarder;
34 import com.android.tradefed.targetprep.BuildError;
35 import com.android.tradefed.targetprep.ITargetCleaner;
36 import com.android.tradefed.targetprep.ITargetPreparer;
37 import com.android.tradefed.targetprep.TargetSetupError;
38 import com.android.tradefed.testtype.IAbi;
39 import com.android.tradefed.testtype.IAbiReceiver;
40 import com.android.tradefed.testtype.IBuildReceiver;
41 import com.android.tradefed.testtype.IDeviceTest;
42 import com.android.tradefed.testtype.IInvocationContextReceiver;
43 import com.android.tradefed.testtype.IRemoteTest;
44 import com.android.tradefed.testtype.IRuntimeHintProvider;
45 import com.android.tradefed.testtype.ITestCollector;
46 import com.android.tradefed.testtype.ITestFilterReceiver;
47 import com.android.tradefed.util.AbiUtils;
48 
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Set;
55 import java.util.concurrent.TimeUnit;
56 
57 /**
58  * Container for Compatibility test module info.
59  *
60  * @deprecated This class is associated with {@link CompatibilityTest} which is deprecate
61  */
62 @Deprecated
63 public class ModuleDef implements IModuleDef {
64 
65     private final String mId;
66     private final String mName;
67     private final IAbi mAbi;
68     private final Set<String> mTokens = new HashSet<>();
69     private IRemoteTest mTest = null;
70     private List<ITargetPreparer> mDynamicConfigPreparers = new ArrayList<>();
71     private List<ITargetPreparer> mPreconditions = new ArrayList<>();
72     private List<ITargetPreparer> mPreparers = new ArrayList<>();
73     private List<ITargetCleaner> mCleaners = new ArrayList<>();
74     private IBuildInfo mBuild;
75     private ITestDevice mDevice;
76     private Set<String> mPreparerAllowlist = new HashSet<>();
77     private ConfigurationDescriptor mConfigurationDescriptor;
78     private IInvocationContext mContext;
79 
ModuleDef(String name, IAbi abi, IRemoteTest test, List<ITargetPreparer> preparers, ConfigurationDescriptor configurationDescriptor)80     public ModuleDef(String name, IAbi abi, IRemoteTest test,
81             List<ITargetPreparer> preparers, ConfigurationDescriptor configurationDescriptor) {
82         mId = AbiUtils.createId(abi.getName(), name);
83         mName = name;
84         mAbi = abi;
85         mTest = test;
86         mConfigurationDescriptor = configurationDescriptor;
87         initializePrepareLists(preparers);
88     }
89 
90     /**
91      * Sort preparers into different lists according to their types
92      *
93      * @param preparers target preparers
94      * @throws IllegalArgumentException
95      */
initializePrepareLists(List<ITargetPreparer> preparers)96     protected void initializePrepareLists(List<ITargetPreparer> preparers)
97             throws IllegalArgumentException {
98         boolean hasAbiReceiver = false;
99         for (ITargetPreparer preparer : preparers) {
100             if (preparer instanceof IAbiReceiver) {
101                 hasAbiReceiver = true;
102             }
103             // Separate preconditions and dynamicconfigpushers from other target preparers.
104             if (preparer instanceof PreconditionPreparer) {
105                 mPreconditions.add(preparer);
106             } else if (preparer instanceof DynamicConfigPusher) {
107                 mDynamicConfigPreparers.add(preparer);
108             } else if (preparer instanceof TokenRequirement) {
109                 mTokens.addAll(((TokenRequirement) preparer).getTokens());
110             } else {
111                 mPreparers.add(preparer);
112             }
113             if (preparer instanceof ITargetCleaner) {
114                 mCleaners.add((ITargetCleaner) preparer);
115             }
116         }
117         // Reverse cleaner order
118         Collections.reverse(mCleaners);
119 
120         checkRequiredInterfaces(hasAbiReceiver);
121     }
122 
123     /**
124      * Check whether required interfaces are implemented.
125      *
126      * @param hasAbiReceiver whether at lease one of the preparers is AbiReceiver
127      * @throws IllegalArgumentException
128      */
checkRequiredInterfaces(boolean hasAbiReceiver)129     protected void checkRequiredInterfaces(boolean hasAbiReceiver) throws IllegalArgumentException {
130         // Required interfaces:
131         if (!hasAbiReceiver && !(mTest instanceof IAbiReceiver)) {
132             throw new IllegalArgumentException(mTest + "does not implement IAbiReceiver"
133                     + " - for multi-abi testing (64bit)");
134         } else if (!(mTest instanceof IRuntimeHintProvider)) {
135             throw new IllegalArgumentException(mTest + " does not implement IRuntimeHintProvider"
136                     + " - to provide estimates of test invocation time");
137         } else if (!(mTest instanceof ITestCollector)) {
138             throw new IllegalArgumentException(mTest + " does not implement ITestCollector"
139                     + " - for test list collection");
140         } else if (!(mTest instanceof ITestFilterReceiver)) {
141             throw new IllegalArgumentException(mTest + " does not implement ITestFilterReceiver"
142                     + " - to allow tests to be filtered");
143         }
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
toString()150     public String toString() {
151         return mId;
152     }
153 
154     /**
155      * {@inheritDoc}
156      */
157     @Override
getId()158     public String getId() {
159         return mId;
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
getName()166     public String getName() {
167         return mName;
168     }
169 
170     /** @return the getPreparerAllowlist */
getPreparerAllowlist()171     protected Set<String> getPreparerAllowlist() {
172         return mPreparerAllowlist;
173     }
174 
175     /**
176      * {@inheritDoc}
177      */
178     @Override
getAbi()179     public IAbi getAbi() {
180         return mAbi;
181     }
182 
183     /**
184      * {@inheritDoc}
185      */
186     @Override
getTokens()187     public Set<String> getTokens() {
188         return mTokens;
189     }
190 
191     /**
192      * {@inheritDoc}
193      */
194     @Override
getRuntimeHint()195     public long getRuntimeHint() {
196         if (mTest instanceof IRuntimeHintProvider) {
197             return ((IRuntimeHintProvider) mTest).getRuntimeHint();
198         }
199         return TimeUnit.MINUTES.toMillis(1); // Default 1 minute.
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     @Override
getTest()206     public IRemoteTest getTest() {
207         return mTest;
208     }
209 
210     /** {@inheritDoc} */
211     @Override
setPreparerAllowlist(Set<String> preparerAlowlist)212     public void setPreparerAllowlist(Set<String> preparerAlowlist) {
213         mPreparerAllowlist.addAll(preparerAlowlist);
214     }
215 
216     /**
217      * {@inheritDoc}
218      */
219     @Override
compareTo(IModuleDef moduleDef)220     public int compareTo(IModuleDef moduleDef) {
221         return getName().compareTo(moduleDef.getName());
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     @Override
setBuild(IBuildInfo build)228     public void setBuild(IBuildInfo build) {
229         mBuild = build;
230     }
231 
232     /**
233      * {@inheritDoc}
234      */
235     @Override
getDevice()236     public ITestDevice getDevice() {
237         return mDevice;
238     }
239 
240     /**
241      * {@inheritDoc}
242      */
243     @Override
setDevice(ITestDevice device)244     public void setDevice(ITestDevice device) {
245         mDevice = device;
246     }
247 
248     /**
249      * {@inheritDoc}
250      */
251     @Override
run(ITestInvocationListener listener)252     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
253         CLog.d("Running module %s", toString());
254         runPreparerSetups();
255 
256         CLog.d("Test: %s", mTest.getClass().getSimpleName());
257         prepareTestClass();
258 
259         IModuleListener moduleListener = new ModuleListener(this, listener);
260         // Guarantee events testRunStarted and testRunEnded in case underlying test runner does not
261         ModuleFinisher moduleFinisher = new ModuleFinisher(moduleListener);
262         mTest.run(moduleFinisher);
263         moduleFinisher.finish();
264 
265         // Tear down
266         runPreparerTeardowns();
267     }
268 
269     /**
270      * Run preparers' teardown functions.
271      */
runPreparerTeardowns()272     protected void runPreparerTeardowns() throws DeviceNotAvailableException {
273         for (ITargetCleaner cleaner : mCleaners) {
274             CLog.d("Cleaner: %s", cleaner.getClass().getSimpleName());
275             cleaner.tearDown(mDevice, mBuild, null);
276         }
277     }
278 
279     /**
280      * Run preparers' setup functions.
281      *
282      * @throws DeviceNotAvailableException
283      */
runPreparerSetups()284     protected void runPreparerSetups() throws DeviceNotAvailableException {
285         // Run DynamicConfigPusher setup once more, in case cleaner has previously
286         // removed dynamic config file from the target (see b/32877809)
287         for (ITargetPreparer preparer : mDynamicConfigPreparers) {
288             runPreparerSetup(preparer);
289         }
290         // Setup
291         for (ITargetPreparer preparer : mPreparers) {
292             runPreparerSetup(preparer);
293         }
294     }
295 
296     /**
297      * Set test classes attributes according to their interfaces.
298      */
prepareTestClass()299     protected void prepareTestClass() {
300         if (mTest instanceof IAbiReceiver) {
301             ((IAbiReceiver) mTest).setAbi(mAbi);
302         }
303         if (mTest instanceof IBuildReceiver) {
304             ((IBuildReceiver) mTest).setBuild(mBuild);
305         }
306         if (mTest instanceof IDeviceTest) {
307             ((IDeviceTest) mTest).setDevice(mDevice);
308         }
309         if (mTest instanceof IInvocationContextReceiver) {
310             ((IInvocationContextReceiver) mTest).setInvocationContext(mContext);
311         }
312     }
313 
314     /**
315      * {@inheritDoc}
316      */
317     @Override
prepare(boolean skipPrep, List<String> preconditionArgs)318     public boolean prepare(boolean skipPrep, List<String> preconditionArgs)
319             throws DeviceNotAvailableException {
320         for (ITargetPreparer preparer : mDynamicConfigPreparers) {
321             runPreparerSetup(preparer);
322         }
323         for (ITargetPreparer preparer : mPreconditions) {
324             setOption(preparer, CompatibilityTest.SKIP_PRECONDITIONS_OPTION,
325                     Boolean.toString(skipPrep));
326             for (String preconditionArg : preconditionArgs) {
327                 setOption(preparer, CompatibilityTest.PRECONDITION_ARG_OPTION, preconditionArg);
328             }
329             try {
330                 runPreparerSetup(preparer);
331             } catch (RuntimeException e) {
332                 CLog.e("Precondition class %s failed", preparer.getClass().getCanonicalName());
333                 return false;
334             }
335         }
336         return true;
337     }
338 
runPreparerSetup(ITargetPreparer preparer)339     private void runPreparerSetup(ITargetPreparer preparer) throws DeviceNotAvailableException {
340         String preparerName = preparer.getClass().getCanonicalName();
341         if (!mPreparerAllowlist.isEmpty() && !mPreparerAllowlist.contains(preparerName)) {
342             CLog.d(
343                     "Skipping Preparer: %s since it is not in the allowList %s",
344                     preparerName, mPreparerAllowlist);
345             return;
346         }
347         CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
348         if (preparer instanceof IAbiReceiver) {
349             ((IAbiReceiver) preparer).setAbi(mAbi);
350         }
351         try {
352             preparer.setUp(mDevice, mBuild);
353         } catch (BuildError e) {
354             // This should only happen for flashing new build
355             CLog.e("Unexpected BuildError from preparer: %s",
356                     preparer.getClass().getCanonicalName());
357             throw new RuntimeException(e);
358         } catch (TargetSetupError e) {
359             // log preparer class then rethrow & let caller handle
360             CLog.e("TargetSetupError in preparer: %s",
361                     preparer.getClass().getCanonicalName());
362             throw new RuntimeException(e);
363         }
364     }
365 
setOption(Object target, String option, String value)366     private void setOption(Object target, String option, String value) {
367         try {
368             OptionSetter setter = new OptionSetter(target);
369             setter.setOptionValue(option, value);
370         } catch (ConfigurationException e) {
371             CLog.e(e);
372         }
373     }
374 
375     /**
376      * {@inheritDoc}
377      */
378     @Override
setCollectTestsOnly(boolean collectTestsOnly)379     public void setCollectTestsOnly(boolean collectTestsOnly) {
380         ((ITestCollector) mTest).setCollectTestsOnly(collectTestsOnly);
381     }
382 
383     /*
384      * ResultForwarder that tracks whether method testRunStarted() has been called for its
385      * listener. If not, invoking finish() will call testRunStarted with 0 tests for this module,
386      * as well as testRunEnded with 0 ms elapsed.
387      */
388     private class ModuleFinisher extends ResultForwarder {
389 
390         private boolean mFinished;
391         private ITestInvocationListener mListener;
392 
ModuleFinisher(ITestInvocationListener listener)393         public ModuleFinisher(ITestInvocationListener listener) {
394             super(listener);
395             mListener = listener;
396             mFinished = false;
397         }
398 
399         /**
400          * {@inheritDoc}
401          */
402         @Override
testRunStarted(String name, int numTests)403         public void testRunStarted(String name, int numTests) {
404             mListener.testRunStarted(name, numTests);
405             mFinished = true;
406         }
407 
finish()408         public void finish() {
409             if (!mFinished) {
410                 mListener.testRunStarted(mId, 0);
411                 mListener.testRunEnded(0, new HashMap<String, Metric>());
412             }
413         }
414     }
415 
416     @Override
getConfigurationDescriptor()417     public ConfigurationDescriptor getConfigurationDescriptor() {
418         return mConfigurationDescriptor;
419     }
420 
421     /**
422      * @return the {@link IInvocationContext} for the module
423      */
getInvocationContext()424     protected IInvocationContext getInvocationContext() {
425         return mContext;
426     }
427 
428     @Override
setInvocationContext(IInvocationContext invocationContext)429     public void setInvocationContext(IInvocationContext invocationContext) {
430         mContext = invocationContext;
431     }
432 }
433