1 /* 2 * Copyright (C) 2017 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.device.metric; 17 18 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey; 19 import com.android.tradefed.build.IBuildInfo; 20 import com.android.tradefed.build.IDeviceBuildInfo; 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.IDeviceActionReceiver; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.device.StubDevice; 26 import com.android.tradefed.invoker.IInvocationContext; 27 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 28 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 29 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 30 import com.android.tradefed.log.LogUtil.CLog; 31 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 32 import com.android.tradefed.result.FailureDescription; 33 import com.android.tradefed.result.ILogSaver; 34 import com.android.tradefed.result.ILogSaverListener; 35 import com.android.tradefed.result.ITestInvocationListener; 36 import com.android.tradefed.result.InputStreamSource; 37 import com.android.tradefed.result.LogDataType; 38 import com.android.tradefed.result.LogFile; 39 import com.android.tradefed.result.TestDescription; 40 import com.android.tradefed.result.proto.TestRecordProto.FailureStatus; 41 import com.android.tradefed.result.skipped.SkipReason; 42 import com.android.tradefed.testtype.suite.ModuleDefinition; 43 import com.android.tradefed.util.FileUtil; 44 import com.android.tradefed.util.SearchArtifactUtil; 45 46 import java.io.File; 47 import java.io.IOException; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.HashSet; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.Set; 55 import java.util.stream.Collectors; 56 57 /** 58 * Base implementation of {@link IMetricCollector} that allows to start and stop collection on 59 * {@link #onTestRunStart(DeviceMetricData)} and {@link #onTestRunEnd(DeviceMetricData, Map)}. 60 */ 61 public class BaseDeviceMetricCollector implements IMetricCollector, IDeviceActionReceiver { 62 63 public static final String TEST_CASE_INCLUDE_GROUP_OPTION = "test-case-include-group"; 64 public static final String TEST_CASE_EXCLUDE_GROUP_OPTION = "test-case-exclude-group"; 65 66 @Option(name = "disable", description = "disables the metrics collector") 67 private boolean mDisable = false; 68 69 @Option( 70 name = TEST_CASE_INCLUDE_GROUP_OPTION, 71 description = 72 "Specify a group to include as part of the collection," 73 + "group can be specified via @MetricOption. Can be repeated." 74 + "Usage: @MetricOption(group = \"groupname\") to your test methods, then" 75 + "use --test-case-include-anotation groupename to only run your group." 76 ) 77 private List<String> mTestCaseIncludeAnnotationGroup = new ArrayList<>(); 78 79 @Option( 80 name = TEST_CASE_EXCLUDE_GROUP_OPTION, 81 description = 82 "Specify a group to exclude from the metric collection," 83 + "group can be specified via @MetricOption. Can be repeated." 84 ) 85 private List<String> mTestCaseExcludeAnnotationGroup = new ArrayList<>(); 86 87 private IInvocationContext mContext; 88 private List<ITestDevice> mRealDeviceList; 89 private ITestInvocationListener mForwarder; 90 private Map<String, File> mTestArtifactFilePathMap = new HashMap<>(); 91 private DeviceMetricData mRunData; 92 private DeviceMetricData mTestData; 93 private String mRunName; 94 95 /** 96 * Variable for whether or not to skip the collection of one test case because it was filtered. 97 */ 98 private boolean mSkipTestCase = false; 99 /** Whether or not the collector was initialized already or not. */ 100 private boolean mWasInitDone = false; 101 /** Whether or not a DNAE occurred and we should stop collection. */ 102 private boolean mDeviceNoAvailable = false; 103 /** Whether the {@link IDeviceActionReceiver} should be disabled or not. */ 104 private boolean mDisableReceiver = true; 105 106 @Override init( IInvocationContext context, ITestInvocationListener listener)107 public final ITestInvocationListener init( 108 IInvocationContext context, ITestInvocationListener listener) 109 throws DeviceNotAvailableException { 110 mContext = context; 111 mForwarder = listener; 112 if (mWasInitDone) { 113 throw new IllegalStateException( 114 String.format("init was called a second time on %s", this)); 115 } 116 mWasInitDone = true; 117 mDeviceNoAvailable = false; 118 // Register this collector for device action events. 119 if (!isDisabledReceiver()) { 120 for (ITestDevice device : getRealDevices()) { 121 device.registerDeviceActionReceiver(this); 122 } 123 } 124 long start = System.currentTimeMillis(); 125 try { 126 extraInit(context, listener); 127 } finally { 128 InvocationMetricLogger.addInvocationMetrics( 129 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 130 } 131 return this; 132 } 133 134 /** 135 * @param context 136 * @param listener 137 * @throws DeviceNotAvailableException 138 */ extraInit(IInvocationContext context, ITestInvocationListener listener)139 public void extraInit(IInvocationContext context, ITestInvocationListener listener) 140 throws DeviceNotAvailableException { 141 // Empty by default 142 } 143 144 @Override getDevices()145 public final List<ITestDevice> getDevices() { 146 return mContext.getDevices(); 147 } 148 149 /** Returns all the non-stub devices from the {@link #getDevices()} list. */ getRealDevices()150 public final List<ITestDevice> getRealDevices() { 151 if (mRealDeviceList == null) { 152 mRealDeviceList = 153 mContext.getDevices() 154 .stream() 155 .filter(d -> !(d.getIDevice() instanceof StubDevice)) 156 .collect(Collectors.toList()); 157 } 158 return mRealDeviceList; 159 } 160 161 /** 162 * Retrieve the file from the test artifacts or module artifacts and cache 163 * it in a map for the subsequent calls. 164 * 165 * @param fileName name of the file to look up in the artifacts. 166 * @return File from the test artifact or module artifact. Returns null 167 * if file is not found. 168 */ getFileFromTestArtifacts(String fileName)169 public File getFileFromTestArtifacts(String fileName) { 170 if (mTestArtifactFilePathMap.containsKey(fileName)) { 171 return mTestArtifactFilePathMap.get(fileName); 172 } 173 174 File resolvedFile = resolveRelativeFilePath(fileName); 175 if (resolvedFile != null) { 176 CLog.i("Using file %s from %s", fileName, resolvedFile.getAbsolutePath()); 177 mTestArtifactFilePathMap.put(fileName, resolvedFile); 178 } 179 return resolvedFile; 180 } 181 182 @Override getBuildInfos()183 public final List<IBuildInfo> getBuildInfos() { 184 return mContext.getBuildInfos(); 185 } 186 187 @Override getInvocationListener()188 public final ITestInvocationListener getInvocationListener() { 189 return mForwarder; 190 } 191 192 @Override onTestModuleStarted()193 public void onTestModuleStarted() throws DeviceNotAvailableException { 194 // Does nothing 195 } 196 197 @Override onTestModuleEnded()198 public void onTestModuleEnded() throws DeviceNotAvailableException { 199 // Does nothing 200 } 201 202 @Override onTestRunStart(DeviceMetricData runData)203 public void onTestRunStart(DeviceMetricData runData) throws DeviceNotAvailableException { 204 // Does nothing 205 } 206 207 /** 208 * Callback for testRunFailed events 209 * 210 * @param testData 211 * @param failure 212 * @throws DeviceNotAvailableException 213 */ onTestRunFailed(DeviceMetricData testData, FailureDescription failure)214 public void onTestRunFailed(DeviceMetricData testData, FailureDescription failure) 215 throws DeviceNotAvailableException { 216 // Does nothing 217 } 218 219 @Override onTestRunEnd(DeviceMetricData runData, final Map<String, Metric> currentRunMetrics)220 public void onTestRunEnd(DeviceMetricData runData, final Map<String, Metric> currentRunMetrics) 221 throws DeviceNotAvailableException { 222 // Does nothing 223 } 224 225 @Override onTestStart(DeviceMetricData testData)226 public void onTestStart(DeviceMetricData testData) throws DeviceNotAvailableException { 227 // Does nothing 228 } 229 230 @Override onTestFail(DeviceMetricData testData, TestDescription test)231 public void onTestFail(DeviceMetricData testData, TestDescription test) 232 throws DeviceNotAvailableException { 233 // Does nothing 234 } 235 236 @Override onTestAssumptionFailure(DeviceMetricData testData, TestDescription test)237 public void onTestAssumptionFailure(DeviceMetricData testData, TestDescription test) 238 throws DeviceNotAvailableException { 239 // Does nothing 240 } 241 242 @Override onTestEnd( DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics)243 public void onTestEnd( 244 DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics) 245 throws DeviceNotAvailableException { 246 // Does nothing 247 } 248 249 @Override onTestEnd( DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics, TestDescription test)250 public void onTestEnd( 251 DeviceMetricData testData, 252 final Map<String, Metric> currentTestCaseMetrics, 253 TestDescription test) 254 throws DeviceNotAvailableException { 255 // Call the default implementation of onTestEnd if not overridden 256 onTestEnd(testData, currentTestCaseMetrics); 257 } 258 259 /** =================================== */ 260 /** Invocation Listeners for forwarding */ 261 @Override invocationStarted(IInvocationContext context)262 public final void invocationStarted(IInvocationContext context) { 263 mForwarder.invocationStarted(context); 264 } 265 266 @Override invocationFailed(Throwable cause)267 public final void invocationFailed(Throwable cause) { 268 mForwarder.invocationFailed(cause); 269 } 270 271 @Override invocationFailed(FailureDescription failure)272 public final void invocationFailed(FailureDescription failure) { 273 mForwarder.invocationFailed(failure); 274 } 275 276 @Override invocationSkipped(SkipReason reason)277 public void invocationSkipped(SkipReason reason) { 278 mForwarder.invocationSkipped(reason); 279 } 280 281 @Override invocationEnded(long elapsedTime)282 public final void invocationEnded(long elapsedTime) { 283 mForwarder.invocationEnded(elapsedTime); 284 } 285 286 @Override testLog(String dataName, LogDataType dataType, InputStreamSource dataStream)287 public final void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) { 288 mForwarder.testLog(dataName, dataType, dataStream); 289 } 290 291 @Override testModuleStarted(IInvocationContext moduleContext)292 public final void testModuleStarted(IInvocationContext moduleContext) { 293 long start = System.currentTimeMillis(); 294 try (CloseableTraceScope ignored = 295 new CloseableTraceScope("module_start_" + this.getClass().getSimpleName())) { 296 onTestModuleStarted(); 297 } catch (DeviceNotAvailableException dnae) { 298 mDeviceNoAvailable = true; 299 CLog.e(dnae); 300 } catch (Throwable t) { 301 CLog.e(t); 302 } finally { 303 InvocationMetricLogger.addInvocationMetrics( 304 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 305 mForwarder.testModuleStarted(moduleContext); 306 } 307 } 308 309 @Override testModuleEnded()310 public final void testModuleEnded() { 311 long start = System.currentTimeMillis(); 312 try (CloseableTraceScope ignored = 313 new CloseableTraceScope("module_end_" + this.getClass().getSimpleName())) { 314 onTestModuleEnded(); 315 } catch (DeviceNotAvailableException dnae) { 316 CLog.e(dnae); 317 } catch (Throwable t) { 318 CLog.e(t); 319 } finally { 320 // De-register this collector from device action events 321 if (!isDisabledReceiver()) { 322 for (ITestDevice device : getRealDevices()) { 323 device.deregisterDeviceActionReceiver(this); 324 } 325 } 326 InvocationMetricLogger.addInvocationMetrics( 327 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 328 mForwarder.testModuleEnded(); 329 } 330 } 331 332 /** Test run callbacks */ 333 @Override testRunStarted(String runName, int testCount)334 public final void testRunStarted(String runName, int testCount) { 335 testRunStarted(runName, testCount, 0); 336 } 337 338 @Override testRunStarted(String runName, int testCount, int attemptNumber)339 public final void testRunStarted(String runName, int testCount, int attemptNumber) { 340 testRunStarted(runName, testCount, 0, System.currentTimeMillis()); 341 } 342 343 @Override testRunStarted( String runName, int testCount, int attemptNumber, long startTime)344 public final void testRunStarted( 345 String runName, int testCount, int attemptNumber, long startTime) { 346 mRunData = new DeviceMetricData(mContext); 347 mRunName = runName; 348 mDeviceNoAvailable = false; 349 long start = System.currentTimeMillis(); 350 try (CloseableTraceScope ignored = 351 new CloseableTraceScope("run_start_" + this.getClass().getSimpleName())) { 352 onTestRunStart(mRunData, testCount); 353 } catch (DeviceNotAvailableException e) { 354 mDeviceNoAvailable = true; 355 CLog.e(e); 356 } catch (Throwable t) { 357 // Prevent exception from messing up the status reporting. 358 CLog.e(t); 359 } finally { 360 InvocationMetricLogger.addInvocationMetrics( 361 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 362 } 363 mForwarder.testRunStarted(runName, testCount, attemptNumber, startTime); 364 } 365 366 @Override testRunFailed(String errorMessage)367 public final void testRunFailed(String errorMessage) { 368 if (!mDeviceNoAvailable) { 369 long start = System.currentTimeMillis(); 370 try { 371 onTestRunFailed(mRunData, FailureDescription.create(errorMessage)); 372 } catch (DeviceNotAvailableException e) { 373 mDeviceNoAvailable = true; 374 CLog.e(e); 375 } catch (Throwable t) { 376 // Prevent exception from messing up the status reporting. 377 CLog.e(t); 378 } finally { 379 InvocationMetricLogger.addInvocationMetrics( 380 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 381 } 382 } 383 mForwarder.testRunFailed(errorMessage); 384 } 385 386 @Override testRunFailed(FailureDescription failure)387 public final void testRunFailed(FailureDescription failure) { 388 if (!mDeviceNoAvailable) { 389 long start = System.currentTimeMillis(); 390 try { 391 onTestRunFailed(mRunData, failure); 392 } catch (DeviceNotAvailableException e) { 393 mDeviceNoAvailable = true; 394 CLog.e(e); 395 } catch (Throwable t) { 396 // Prevent exception from messing up the status reporting. 397 CLog.e(t); 398 } finally { 399 InvocationMetricLogger.addInvocationMetrics( 400 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 401 } 402 } 403 mForwarder.testRunFailed(failure); 404 } 405 406 @Override testRunStopped(long elapsedTime)407 public final void testRunStopped(long elapsedTime) { 408 mForwarder.testRunStopped(elapsedTime); 409 } 410 411 @Override testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics)412 public final void testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics) { 413 if (!mDeviceNoAvailable) { 414 long start = System.currentTimeMillis(); 415 try (CloseableTraceScope ignored = 416 new CloseableTraceScope("run_end_" + this.getClass().getSimpleName())) { 417 onTestRunEnd(mRunData, runMetrics); 418 mRunData.addToMetrics(runMetrics); 419 } catch (DeviceNotAvailableException e) { 420 mDeviceNoAvailable = true; 421 CLog.e(e); 422 } catch (Throwable t) { 423 // Prevent exception from messing up the status reporting. 424 CLog.e(t); 425 } finally { 426 // De-register this collector from device action events 427 if (!isDisabledReceiver()) { 428 for (ITestDevice device : getRealDevices()) { 429 device.deregisterDeviceActionReceiver(this); 430 } 431 } 432 InvocationMetricLogger.addInvocationMetrics( 433 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 434 } 435 } 436 mForwarder.testRunEnded(elapsedTime, runMetrics); 437 } 438 439 /** Test cases callbacks */ 440 @Override testStarted(TestDescription test)441 public final void testStarted(TestDescription test) { 442 testStarted(test, System.currentTimeMillis()); 443 } 444 445 @Override testStarted(TestDescription test, long startTime)446 public final void testStarted(TestDescription test, long startTime) { 447 if (!mDeviceNoAvailable) { 448 mTestData = new DeviceMetricData(mContext); 449 mSkipTestCase = shouldSkip(test); 450 if (!mSkipTestCase) { 451 long start = System.currentTimeMillis(); 452 try { 453 onTestStart(mTestData); 454 } catch (DeviceNotAvailableException e) { 455 mDeviceNoAvailable = true; 456 CLog.e(e); 457 } catch (Throwable t) { 458 // Prevent exception from messing up the status reporting. 459 CLog.e(t); 460 } finally { 461 InvocationMetricLogger.addInvocationMetrics( 462 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 463 } 464 } 465 } 466 mForwarder.testStarted(test, startTime); 467 } 468 469 @Override testFailed(TestDescription test, String trace)470 public final void testFailed(TestDescription test, String trace) { 471 if (!mSkipTestCase && !mDeviceNoAvailable) { 472 long start = System.currentTimeMillis(); 473 try { 474 onTestFail(mTestData, test); 475 } catch (DeviceNotAvailableException e) { 476 mDeviceNoAvailable = true; 477 CLog.e(e); 478 } catch (Throwable t) { 479 // Prevent exception from messing up the status reporting. 480 CLog.e(t); 481 } finally { 482 InvocationMetricLogger.addInvocationMetrics( 483 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 484 } 485 } 486 mForwarder.testFailed(test, trace); 487 } 488 489 @Override testFailed(TestDescription test, FailureDescription failure)490 public final void testFailed(TestDescription test, FailureDescription failure) { 491 if (!mSkipTestCase && !mDeviceNoAvailable) { 492 // Don't collect on not_executed test case 493 if (failure.getFailureStatus() == null 494 || !FailureStatus.NOT_EXECUTED.equals(failure.getFailureStatus())) { 495 long start = System.currentTimeMillis(); 496 try { 497 onTestFail(mTestData, test); 498 } catch (DeviceNotAvailableException e) { 499 mDeviceNoAvailable = true; 500 CLog.e(e); 501 } catch (Throwable t) { 502 // Prevent exception from messing up the status reporting. 503 CLog.e(t); 504 } finally { 505 InvocationMetricLogger.addInvocationMetrics( 506 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 507 } 508 } 509 } 510 mForwarder.testFailed(test, failure); 511 } 512 513 @Override testEnded(TestDescription test, HashMap<String, Metric> testMetrics)514 public final void testEnded(TestDescription test, HashMap<String, Metric> testMetrics) { 515 testEnded(test, System.currentTimeMillis(), testMetrics); 516 } 517 518 @Override testEnded( TestDescription test, long endTime, HashMap<String, Metric> testMetrics)519 public final void testEnded( 520 TestDescription test, long endTime, HashMap<String, Metric> testMetrics) { 521 if (!mSkipTestCase && !mDeviceNoAvailable) { 522 long start = System.currentTimeMillis(); 523 try { 524 onTestEnd(mTestData, testMetrics, test); 525 mTestData.addToMetrics(testMetrics); 526 } catch (DeviceNotAvailableException e) { 527 mDeviceNoAvailable = true; 528 CLog.e(e); 529 } catch (Throwable t) { 530 // Prevent exception from messing up the status reporting. 531 CLog.e(t); 532 } finally { 533 InvocationMetricLogger.addInvocationMetrics( 534 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 535 } 536 } else { 537 CLog.d("Skipping %s collection for %s.", this.getClass().getName(), test.toString()); 538 } 539 mForwarder.testEnded(test, endTime, testMetrics); 540 } 541 542 @Override testSkipped(TestDescription test, SkipReason reason)543 public final void testSkipped(TestDescription test, SkipReason reason) { 544 mForwarder.testSkipped(test, reason); 545 } 546 547 @Override testAssumptionFailure(TestDescription test, String trace)548 public final void testAssumptionFailure(TestDescription test, String trace) { 549 if (!mSkipTestCase && !mDeviceNoAvailable) { 550 long start = System.currentTimeMillis(); 551 try { 552 onTestAssumptionFailure(mTestData, test); 553 } catch (DeviceNotAvailableException e) { 554 mDeviceNoAvailable = true; 555 CLog.e(e); 556 } catch (Throwable t) { 557 // Prevent exception from messing up the status reporting. 558 CLog.e(t); 559 } finally { 560 InvocationMetricLogger.addInvocationMetrics( 561 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 562 } 563 } 564 mForwarder.testAssumptionFailure(test, trace); 565 } 566 567 @Override testAssumptionFailure(TestDescription test, FailureDescription failure)568 public final void testAssumptionFailure(TestDescription test, FailureDescription failure) { 569 if (!mSkipTestCase && !mDeviceNoAvailable) { 570 long start = System.currentTimeMillis(); 571 try { 572 onTestAssumptionFailure(mTestData, test); 573 } catch (DeviceNotAvailableException e) { 574 mDeviceNoAvailable = true; 575 CLog.e(e); 576 } catch (Throwable t) { 577 // Prevent exception from messing up the status reporting. 578 CLog.e(t); 579 } finally { 580 InvocationMetricLogger.addInvocationMetrics( 581 InvocationMetricKey.COLLECTOR_TIME, System.currentTimeMillis() - start); 582 } 583 } 584 mForwarder.testAssumptionFailure(test, failure); 585 } 586 587 @Override testIgnored(TestDescription test)588 public final void testIgnored(TestDescription test) { 589 mForwarder.testIgnored(test); 590 } 591 592 /** 593 * Do not use inside metric collector implementation. This is pure forwarding. 594 */ 595 @Override setLogSaver(ILogSaver logSaver)596 public final void setLogSaver(ILogSaver logSaver) { 597 if (mForwarder instanceof ILogSaverListener) { 598 ((ILogSaverListener) mForwarder).setLogSaver(logSaver); 599 } 600 } 601 602 /** 603 * Do not use inside metric collector implementation. This is pure forwarding. 604 */ 605 @Override logAssociation(String dataName, LogFile logFile)606 public final void logAssociation(String dataName, LogFile logFile) { 607 if (mForwarder instanceof ILogSaverListener) { 608 ((ILogSaverListener) mForwarder).logAssociation(dataName, logFile); 609 } 610 } 611 612 /** 613 * Do not use inside metric collector implementation. This is pure forwarding. 614 */ 615 @Override testLogSaved(String dataName, LogDataType dataType, InputStreamSource dataStream, LogFile logFile)616 public final void testLogSaved(String dataName, LogDataType dataType, 617 InputStreamSource dataStream, LogFile logFile) { 618 if (mForwarder instanceof ILogSaverListener) { 619 ((ILogSaverListener) mForwarder).testLogSaved(dataName, dataType, dataStream, logFile); 620 } 621 } 622 623 /** {@inheritDoc} */ 624 @Override isDisabled()625 public final boolean isDisabled() { 626 return mDisable; 627 } 628 629 /** {@inheritDoc} */ 630 @Override setDisable(boolean isDisabled)631 public final void setDisable(boolean isDisabled) { 632 mDisable = isDisabled; 633 } 634 635 /** 636 * Returns the name of test run {@code mRunName} that triggers the collector. 637 * 638 * @return mRunName, the current test run name. 639 */ getRunName()640 public String getRunName() { 641 return mRunName; 642 } 643 getModuleName()644 public String getModuleName() { 645 return mContext.getAttributes().get(ModuleDefinition.MODULE_NAME) != null 646 ? mContext.getAttributes().get(ModuleDefinition.MODULE_NAME).get(0) 647 : null; 648 } 649 650 /** 651 * Helper to decide if a test case should or not run the collector method associated. 652 * 653 * @param desc the identifier of the test case. 654 * @return True the collector should be skipped. False otherwise. 655 */ shouldSkip(TestDescription desc)656 private boolean shouldSkip(TestDescription desc) { 657 Set<String> testCaseGroups = new HashSet<>(); 658 if (desc.getAnnotation(MetricOption.class) != null) { 659 String groupName = desc.getAnnotation(MetricOption.class).group(); 660 testCaseGroups.addAll(Arrays.asList(groupName.split(","))); 661 } else { 662 // Add empty group name for default case. 663 testCaseGroups.add(""); 664 } 665 // Exclusion has priority: if any of the groups is excluded, exclude the test case. 666 for (String groupName : testCaseGroups) { 667 if (mTestCaseExcludeAnnotationGroup.contains(groupName)) { 668 return true; 669 } 670 } 671 // Inclusion filter: if any of the group is included, include the test case. 672 for (String includeGroupName : mTestCaseIncludeAnnotationGroup) { 673 if (testCaseGroups.contains(includeGroupName)) { 674 return false; 675 } 676 } 677 678 // If we had filters and did not match any groups 679 if (!mTestCaseIncludeAnnotationGroup.isEmpty()) { 680 return true; 681 } 682 return false; 683 } 684 685 /** 686 * Resolves the relative path of the file from the test artifacts 687 * directory or module directory. 688 * 689 * @param fileName file name that needs to be resolved. 690 * @return File file resolved for the given file name. Returns null 691 * if file not found. 692 */ resolveRelativeFilePath(String fileName)693 private File resolveRelativeFilePath(String fileName) { 694 File src = null; 695 try { 696 src = SearchArtifactUtil.searchFile(fileName, true); 697 } catch (Exception e) { 698 // TODO: handle error when migration is complete. 699 CLog.e(e); 700 } 701 if (src != null && src.exists()) { 702 CLog.d("Found '%s' using SearchArtifactUtil", fileName); 703 return src; 704 } else { 705 CLog.d("Did not find '%s' using SearchArtifactUtil, fall back to old logic", fileName); 706 // Silently report not found and fall back to old logic. 707 InvocationMetricLogger.addInvocationMetrics( 708 InvocationMetricKey.SEARCH_ARTIFACT_FAILURE_COUNT, 1); 709 } 710 711 IBuildInfo buildInfo = getBuildInfos().get(0); 712 String mModuleName = null; 713 // Retrieve the module name. 714 if (mContext.getAttributes().get(ModuleDefinition.MODULE_NAME) != null) { 715 mModuleName = mContext.getAttributes().get(ModuleDefinition.MODULE_NAME) 716 .get(0); 717 } 718 719 if (buildInfo != null) { 720 src = buildInfo.getFile(fileName); 721 if (src != null && src.exists()) { 722 return src; 723 } 724 } 725 726 if (buildInfo instanceof IDeviceBuildInfo) { 727 IDeviceBuildInfo deviceBuild = (IDeviceBuildInfo) buildInfo; 728 File testDir = deviceBuild.getTestsDir(); 729 List<File> scanDirs = new ArrayList<>(); 730 // If it exists, always look first in the ANDROID_TARGET_OUT_TESTCASES 731 File targetTestCases = deviceBuild.getFile(BuildInfoFileKey.TARGET_LINKED_DIR); 732 if (targetTestCases != null) { 733 scanDirs.add(targetTestCases); 734 } 735 // If not, look into the test directory. 736 if (testDir != null) { 737 scanDirs.add(testDir); 738 } 739 740 if (mModuleName != null) { 741 // Use module name as a discriminant to find some files 742 if (testDir != null) { 743 try { 744 File moduleDir = FileUtil.findDirectory( 745 mModuleName, scanDirs.toArray(new File[] {})); 746 if (moduleDir != null) { 747 // If the spec is pushing the module itself 748 if (mModuleName.equals(fileName)) { 749 // If that's the main binary generated by the target, we push the 750 // full directory 751 return moduleDir; 752 } 753 // Search the module directory if it exists use it in priority 754 src = FileUtil.findFile(fileName, null, moduleDir); 755 if (src != null) { 756 CLog.i("Retrieving src file from" + src.getAbsolutePath()); 757 return src; 758 } 759 } else { 760 CLog.d("Did not find any module directory for '%s'", mModuleName); 761 } 762 763 } catch (IOException e) { 764 CLog.w( 765 "Something went wrong while searching for the module '%s' " 766 + "directory.", 767 mModuleName); 768 } 769 } 770 } 771 772 for (File searchDir : scanDirs) { 773 try { 774 Set<File> allMatch = FileUtil.findFilesObject(searchDir, fileName); 775 if (allMatch.size() > 1) { 776 CLog.d( 777 "Several match for filename '%s', searching for top-level match.", 778 fileName); 779 for (File f : allMatch) { 780 if (f.getParent().equals(searchDir.getAbsolutePath())) { 781 return f; 782 } 783 } 784 } else if (allMatch.size() == 1) { 785 return allMatch.iterator().next(); 786 } 787 } catch (IOException e) { 788 CLog.w("Failed to find test files from directory."); 789 } 790 } 791 } 792 793 if (src == null) { 794 // if old logic fails too, do not report search artifact failure 795 InvocationMetricLogger.addInvocationMetrics( 796 InvocationMetricKey.SEARCH_ARTIFACT_FAILURE_COUNT, -1); 797 } 798 799 return src; 800 } 801 802 @Override rebootStarted(ITestDevice device)803 public void rebootStarted(ITestDevice device) throws DeviceNotAvailableException { 804 // Does nothing 805 } 806 807 @Override rebootEnded(ITestDevice device)808 public void rebootEnded(ITestDevice device) throws DeviceNotAvailableException { 809 // Does nothing 810 } 811 812 @Override setDisableReceiver(boolean isDisabled)813 public void setDisableReceiver(boolean isDisabled) { 814 mDisableReceiver = isDisabled; 815 } 816 817 @Override isDisabledReceiver()818 public boolean isDisabledReceiver() { 819 return mDisableReceiver; 820 } 821 } 822