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 public class ModuleDef implements IModuleDef { 61 62 private final String mId; 63 private final String mName; 64 private final IAbi mAbi; 65 private final Set<String> mTokens = new HashSet<>(); 66 private IRemoteTest mTest = null; 67 private List<ITargetPreparer> mDynamicConfigPreparers = new ArrayList<>(); 68 private List<ITargetPreparer> mPreconditions = new ArrayList<>(); 69 private List<ITargetPreparer> mPreparers = new ArrayList<>(); 70 private List<ITargetCleaner> mCleaners = new ArrayList<>(); 71 private IBuildInfo mBuild; 72 private ITestDevice mDevice; 73 private Set<String> mPreparerWhitelist = new HashSet<>(); 74 private ConfigurationDescriptor mConfigurationDescriptor; 75 private IInvocationContext mContext; 76 ModuleDef(String name, IAbi abi, IRemoteTest test, List<ITargetPreparer> preparers, ConfigurationDescriptor configurationDescriptor)77 public ModuleDef(String name, IAbi abi, IRemoteTest test, 78 List<ITargetPreparer> preparers, ConfigurationDescriptor configurationDescriptor) { 79 mId = AbiUtils.createId(abi.getName(), name); 80 mName = name; 81 mAbi = abi; 82 mTest = test; 83 mConfigurationDescriptor = configurationDescriptor; 84 initializePrepareLists(preparers); 85 } 86 87 /** 88 * Sort preparers into different lists according to their types 89 * 90 * @param preparers target preparers 91 * @throws IllegalArgumentException 92 */ initializePrepareLists(List<ITargetPreparer> preparers)93 protected void initializePrepareLists(List<ITargetPreparer> preparers) 94 throws IllegalArgumentException { 95 boolean hasAbiReceiver = false; 96 for (ITargetPreparer preparer : preparers) { 97 if (preparer instanceof IAbiReceiver) { 98 hasAbiReceiver = true; 99 } 100 // Separate preconditions and dynamicconfigpushers from other target preparers. 101 if (preparer instanceof PreconditionPreparer) { 102 mPreconditions.add(preparer); 103 } else if (preparer instanceof DynamicConfigPusher) { 104 mDynamicConfigPreparers.add(preparer); 105 } else if (preparer instanceof TokenRequirement) { 106 mTokens.addAll(((TokenRequirement) preparer).getTokens()); 107 } else { 108 mPreparers.add(preparer); 109 } 110 if (preparer instanceof ITargetCleaner) { 111 mCleaners.add((ITargetCleaner) preparer); 112 } 113 } 114 // Reverse cleaner order 115 Collections.reverse(mCleaners); 116 117 checkRequiredInterfaces(hasAbiReceiver); 118 } 119 120 /** 121 * Check whether required interfaces are implemented. 122 * 123 * @param hasAbiReceiver whether at lease one of the preparers is AbiReceiver 124 * @throws IllegalArgumentException 125 */ checkRequiredInterfaces(boolean hasAbiReceiver)126 protected void checkRequiredInterfaces(boolean hasAbiReceiver) throws IllegalArgumentException { 127 // Required interfaces: 128 if (!hasAbiReceiver && !(mTest instanceof IAbiReceiver)) { 129 throw new IllegalArgumentException(mTest + "does not implement IAbiReceiver" 130 + " - for multi-abi testing (64bit)"); 131 } else if (!(mTest instanceof IRuntimeHintProvider)) { 132 throw new IllegalArgumentException(mTest + " does not implement IRuntimeHintProvider" 133 + " - to provide estimates of test invocation time"); 134 } else if (!(mTest instanceof ITestCollector)) { 135 throw new IllegalArgumentException(mTest + " does not implement ITestCollector" 136 + " - for test list collection"); 137 } else if (!(mTest instanceof ITestFilterReceiver)) { 138 throw new IllegalArgumentException(mTest + " does not implement ITestFilterReceiver" 139 + " - to allow tests to be filtered"); 140 } 141 } 142 143 /** 144 * {@inheritDoc} 145 */ 146 @Override toString()147 public String toString() { 148 return mId; 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 @Override getId()155 public String getId() { 156 return mId; 157 } 158 159 /** 160 * {@inheritDoc} 161 */ 162 @Override getName()163 public String getName() { 164 return mName; 165 } 166 167 /** 168 * @return the mPreparerWhitelist 169 */ getPreparerWhitelist()170 protected Set<String> getPreparerWhitelist() { 171 return mPreparerWhitelist; 172 } 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override getAbi()178 public IAbi getAbi() { 179 return mAbi; 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override getTokens()186 public Set<String> getTokens() { 187 return mTokens; 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override getRuntimeHint()194 public long getRuntimeHint() { 195 if (mTest instanceof IRuntimeHintProvider) { 196 return ((IRuntimeHintProvider) mTest).getRuntimeHint(); 197 } 198 return TimeUnit.MINUTES.toMillis(1); // Default 1 minute. 199 } 200 201 /** 202 * {@inheritDoc} 203 */ 204 @Override getTest()205 public IRemoteTest getTest() { 206 return mTest; 207 } 208 209 /** 210 * {@inheritDoc} 211 */ 212 @Override setPreparerWhitelist(Set<String> preparerWhitelist)213 public void setPreparerWhitelist(Set<String> preparerWhitelist) { 214 mPreparerWhitelist.addAll(preparerWhitelist); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 @Override compareTo(IModuleDef moduleDef)221 public int compareTo(IModuleDef moduleDef) { 222 return getName().compareTo(moduleDef.getName()); 223 } 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override setBuild(IBuildInfo build)229 public void setBuild(IBuildInfo build) { 230 mBuild = build; 231 } 232 233 /** 234 * {@inheritDoc} 235 */ 236 @Override getDevice()237 public ITestDevice getDevice() { 238 return mDevice; 239 } 240 241 /** 242 * {@inheritDoc} 243 */ 244 @Override setDevice(ITestDevice device)245 public void setDevice(ITestDevice device) { 246 mDevice = device; 247 } 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override run(ITestInvocationListener listener)253 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 254 CLog.d("Running module %s", toString()); 255 runPreparerSetups(); 256 257 CLog.d("Test: %s", mTest.getClass().getSimpleName()); 258 prepareTestClass(); 259 260 IModuleListener moduleListener = new ModuleListener(this, listener); 261 // Guarantee events testRunStarted and testRunEnded in case underlying test runner does not 262 ModuleFinisher moduleFinisher = new ModuleFinisher(moduleListener); 263 mTest.run(moduleFinisher); 264 moduleFinisher.finish(); 265 266 // Tear down 267 runPreparerTeardowns(); 268 } 269 270 /** 271 * Run preparers' teardown functions. 272 */ runPreparerTeardowns()273 protected void runPreparerTeardowns() throws DeviceNotAvailableException { 274 for (ITargetCleaner cleaner : mCleaners) { 275 CLog.d("Cleaner: %s", cleaner.getClass().getSimpleName()); 276 cleaner.tearDown(mDevice, mBuild, null); 277 } 278 } 279 280 /** 281 * Run preparers' setup functions. 282 * 283 * @throws DeviceNotAvailableException 284 */ runPreparerSetups()285 protected void runPreparerSetups() throws DeviceNotAvailableException { 286 // Run DynamicConfigPusher setup once more, in case cleaner has previously 287 // removed dynamic config file from the target (see b/32877809) 288 for (ITargetPreparer preparer : mDynamicConfigPreparers) { 289 runPreparerSetup(preparer); 290 } 291 // Setup 292 for (ITargetPreparer preparer : mPreparers) { 293 runPreparerSetup(preparer); 294 } 295 } 296 297 /** 298 * Set test classes attributes according to their interfaces. 299 */ prepareTestClass()300 protected void prepareTestClass() { 301 if (mTest instanceof IAbiReceiver) { 302 ((IAbiReceiver) mTest).setAbi(mAbi); 303 } 304 if (mTest instanceof IBuildReceiver) { 305 ((IBuildReceiver) mTest).setBuild(mBuild); 306 } 307 if (mTest instanceof IDeviceTest) { 308 ((IDeviceTest) mTest).setDevice(mDevice); 309 } 310 if (mTest instanceof IInvocationContextReceiver) { 311 ((IInvocationContextReceiver) mTest).setInvocationContext(mContext); 312 } 313 } 314 315 /** 316 * {@inheritDoc} 317 */ 318 @Override prepare(boolean skipPrep, List<String> preconditionArgs)319 public boolean prepare(boolean skipPrep, List<String> preconditionArgs) 320 throws DeviceNotAvailableException { 321 for (ITargetPreparer preparer : mDynamicConfigPreparers) { 322 runPreparerSetup(preparer); 323 } 324 for (ITargetPreparer preparer : mPreconditions) { 325 setOption(preparer, CompatibilityTest.SKIP_PRECONDITIONS_OPTION, 326 Boolean.toString(skipPrep)); 327 for (String preconditionArg : preconditionArgs) { 328 setOption(preparer, CompatibilityTest.PRECONDITION_ARG_OPTION, preconditionArg); 329 } 330 try { 331 runPreparerSetup(preparer); 332 } catch (RuntimeException e) { 333 CLog.e("Precondition class %s failed", preparer.getClass().getCanonicalName()); 334 return false; 335 } 336 } 337 return true; 338 } 339 runPreparerSetup(ITargetPreparer preparer)340 private void runPreparerSetup(ITargetPreparer preparer) throws DeviceNotAvailableException { 341 String preparerName = preparer.getClass().getCanonicalName(); 342 if (!mPreparerWhitelist.isEmpty() && !mPreparerWhitelist.contains(preparerName)) { 343 CLog.d("Skipping Preparer: %s since it is not in the whitelist %s", 344 preparerName, mPreparerWhitelist); 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