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.compatibility.common.tradefed.presubmit; 17 18 import static org.junit.Assert.assertEquals; 19 20 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; 21 import com.android.compatibility.common.tradefed.result.ResultReporter; 22 import com.android.compatibility.common.tradefed.testtype.CompatibilityTest; 23 import com.android.compatibility.common.tradefed.testtype.IModuleDef; 24 import com.android.compatibility.common.util.IInvocationResult; 25 import com.android.compatibility.common.util.TestStatus; 26 import com.android.tradefed.build.IBuildInfo; 27 import com.android.tradefed.config.ConfigurationFactory; 28 import com.android.tradefed.config.OptionSetter; 29 import com.android.tradefed.device.DeviceNotAvailableException; 30 import com.android.tradefed.device.ITestDevice; 31 import com.android.tradefed.invoker.IInvocationContext; 32 import com.android.tradefed.invoker.InvocationContext; 33 import com.android.tradefed.invoker.ShardListener; 34 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 35 import com.android.tradefed.result.ITestInvocationListener; 36 import com.android.tradefed.result.ResultForwarder; 37 import com.android.tradefed.result.TestDescription; 38 import com.android.tradefed.testtype.IBuildReceiver; 39 import com.android.tradefed.testtype.IDeviceTest; 40 import com.android.tradefed.testtype.IInvocationContextReceiver; 41 import com.android.tradefed.testtype.IRemoteTest; 42 import com.android.tradefed.util.AbiUtils; 43 import com.android.tradefed.util.FileUtil; 44 45 import org.easymock.EasyMock; 46 import org.junit.After; 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.junit.runners.JUnit4; 51 52 import java.io.File; 53 import java.io.IOException; 54 import java.util.ArrayList; 55 import java.util.Collections; 56 import java.util.HashMap; 57 import java.util.HashSet; 58 import java.util.List; 59 import java.util.Map; 60 import java.util.Set; 61 62 /** 63 * Integration tests between {@link CompatibilityTest} and {@link ResultReporter} to ensure proper 64 * flow of run and results. 65 */ 66 @RunWith(JUnit4.class) 67 public class IntegrationTest { 68 69 private static final String CONFIG = 70 "<configuration description=\"Auto Generated File\">\n" + 71 "<option name=\"config-descriptor:metadata\" key=\"component\" value=\"%s\" />\n" + 72 "<test class=\"com.android.compatibility.common.tradefed.testtype.%s\">\n" + 73 " <option name=\"report-test\" value=\"%s\" />\n" + 74 " <option name=\"run-complete\" value=\"%s\" />\n" + 75 " <option name=\"test-fail\" value=\"%s\" />\n" + 76 " <option name=\"internal-retry\" value=\"%s\" />\n" + 77 "</test>\n" + 78 "</configuration>"; 79 private static final String FILENAME = "%s.config"; 80 private static final String TEST_STUB = "TestStub"; // Test stub 81 private static final String SIMPLE_TEST_STUB = "SimpleTestStub"; // Simple test stub 82 private static final String TEST_STUB_SHARDABLE = "TestStubShardable"; 83 private static final String COMMAND_LINE = "run cts"; 84 85 private CompatibilityTest mTest; 86 private ResultReporter mReporter; 87 private ITestDevice mMockDevice; 88 private IBuildInfo mMockBuildInfo; 89 private IInvocationContext mContext; 90 91 private File mRootDir; 92 private File mAndroidFolder; 93 private File mTestDir; 94 private Map<String, String> mAttributes; 95 96 @Before setUp()97 public void setUp() throws IOException { 98 mAttributes = new HashMap<>(); 99 mTest = new CompatibilityTest() { 100 @Override 101 protected Set<String> getAbisForBuildTargetArch() { 102 Set<String> abis = new HashSet<>(); 103 abis.add("arm64-v8a"); 104 abis.add("armeabi-v7a"); 105 return abis; 106 } 107 }; 108 mReporter = new ResultReporter(); 109 mMockDevice = EasyMock.createMock(ITestDevice.class); 110 mMockBuildInfo = EasyMock.createMock(IBuildInfo.class); 111 mTest.setBuild(mMockBuildInfo); 112 mTest.setDevice(mMockDevice); 113 mRootDir = FileUtil.createTempDir("fake-cts-root-dir"); 114 mAndroidFolder = FileUtil.createTempDir("android-", mRootDir); 115 mTestDir = new File(mAndroidFolder, "testcases"); 116 mTestDir.mkdirs(); 117 String suiteName = mAndroidFolder.getName().split("-")[1]; 118 // Create fake build attributes 119 mAttributes.put(CompatibilityBuildHelper.ROOT_DIR, mRootDir.getAbsolutePath()); 120 mAttributes.put(CompatibilityBuildHelper.SUITE_NAME, suiteName); 121 mAttributes.put(CompatibilityBuildHelper.START_TIME_MS, "0"); 122 mAttributes.put(CompatibilityBuildHelper.SUITE_VERSION, "10"); 123 mAttributes.put(CompatibilityBuildHelper.SUITE_PLAN, "cts"); 124 mAttributes.put(CompatibilityBuildHelper.SUITE_BUILD, "good-build"); 125 mAttributes.put(CompatibilityBuildHelper.COMMAND_LINE_ARGS, COMMAND_LINE); 126 127 // these attributes seems necessary for re-run, not for run 128 mAttributes.put("cts:build_fingerprint", "fingerprint"); 129 mAttributes.put("cts:build_product", "product"); 130 mAttributes.put("cts:build_id", "bid"); 131 132 EasyMock.expect(mMockBuildInfo.getBuildAttributes()).andStubReturn(mAttributes); 133 134 EasyMock.expect(mMockDevice.getSerialNumber()).andStubReturn("SERIAL"); 135 EasyMock.expect(mMockBuildInfo.getDeviceSerial()).andStubReturn("SERIAL"); 136 137 EasyMock.expect(mMockBuildInfo.getFiles()).andStubReturn(Collections.emptyList()); 138 139 mContext = new InvocationContext(); 140 mContext.addAllocatedDevice("default", mMockDevice); 141 mContext.addDeviceBuildInfo("default", mMockBuildInfo); 142 mTest.setInvocationContext(mContext); 143 } 144 145 @After tearDown()146 public void tearDown() { 147 FileUtil.recursiveDelete(mRootDir); 148 } 149 150 /** 151 * Create a CTS configuration with a fake tests to exercise all cases. 152 * 153 * @param testsDir The testcases/ dir where to put the module 154 * @param name the name of the module. 155 * @param moduleClass the fake test class to use. 156 * @param reportTest True if the test report some tests 157 * @param runComplete True if the test run is complete 158 * @param doesOneTestFail True if one of the test is going to fail 159 * @param internalRetry True if the test will retry the module itself once 160 */ createConfig(File testsDir, String name, String moduleClass, boolean reportTest, boolean runComplete, boolean doesOneTestFail, boolean internalRetry)161 private void createConfig(File testsDir, String name, String moduleClass, boolean reportTest, 162 boolean runComplete, boolean doesOneTestFail, boolean internalRetry) 163 throws IOException { 164 createConfig(testsDir, name, moduleClass, reportTest, runComplete, doesOneTestFail, 165 internalRetry, "foo"); 166 167 } 168 169 /** 170 * Create a CTS configuration with a fake tests to exercise all cases. 171 * 172 * @param testsDir The testcases/ dir where to put the module 173 * @param name the name of the module. 174 * @param moduleClass the fake test class to use. 175 * @param reportTest True if the test report some tests 176 * @param runComplete True if the test run is complete 177 * @param doesOneTestFail True if one of the test is going to fail 178 * @param internalRetry True if the test will retry the module itself once 179 * @param component the platform component name that the module can be categorized under 180 */ createConfig(File testsDir, String name, String moduleClass, boolean reportTest, boolean runComplete, boolean doesOneTestFail, boolean internalRetry, String component)181 private void createConfig(File testsDir, String name, String moduleClass, boolean reportTest, 182 boolean runComplete, boolean doesOneTestFail, boolean internalRetry, String component) 183 throws IOException { 184 File config = new File(testsDir, String.format(FILENAME, name)); 185 FileUtil.deleteFile(config); 186 if (!config.createNewFile()) { 187 throw new IOException(String.format("Failed to create '%s'", config.getAbsolutePath())); 188 } 189 190 FileUtil.writeToFile(String.format(CONFIG, component, moduleClass, reportTest, runComplete, 191 doesOneTestFail, internalRetry), config); 192 } 193 194 /** 195 * Simple tests running in one module that should be marked complete. 196 */ 197 @Test testSingleModuleRun()198 public void testSingleModuleRun() throws Exception { 199 final String moduleName = "module_run"; 200 final String mAbi = "arm64-v8a"; 201 createConfig(mTestDir, moduleName, TEST_STUB, true, true, true, false); 202 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 203 204 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 205 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 206 EasyMock.expectLastCall(); 207 208 EasyMock.replay(mMockDevice, mMockBuildInfo); 209 mReporter.invocationStarted(mContext); 210 mTest.run(mReporter); 211 mReporter.invocationEnded(500); 212 EasyMock.verify(mMockDevice, mMockBuildInfo); 213 IInvocationResult result = mReporter.getResult(); 214 assertEquals(2, result.countResults(TestStatus.PASS)); 215 assertEquals(1, result.countResults(TestStatus.FAIL)); 216 assertEquals(1, result.getModules().size()); 217 assertEquals(1, result.getModuleCompleteCount()); 218 } 219 220 /** 221 * Verify that result reporters test run ended callback can receive component name as configured 222 * in module config metadata field. 223 */ 224 @Test testSingleModuleRun_checkMetadata()225 public void testSingleModuleRun_checkMetadata() throws Exception { 226 final String moduleName = "AwsomeModule"; 227 final String mAbi = "arm64-v8a"; 228 final String component = "CriticalComponent"; 229 final List<String> receivedComponentsTestEnded = new ArrayList<>(); 230 final List<String> receivedModuleNameTestEnded = new ArrayList<>(); 231 final List<String> receivedAbiTestEnded = new ArrayList<>(); 232 final List<String> receivedComponentsTestRunEnded = new ArrayList<>(); 233 final List<String> receivedModuleNameTestRunEnded = new ArrayList<>(); 234 final List<String> receivedAbiTestRunEnded = new ArrayList<>(); 235 createConfig(mTestDir, moduleName, SIMPLE_TEST_STUB, true, true, true, false, component); 236 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 237 238 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 239 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 240 EasyMock.expectLastCall(); 241 242 EasyMock.replay(mMockDevice, mMockBuildInfo); 243 ITestInvocationListener myListener = new ITestInvocationListener() { 244 private IInvocationContext myContext; 245 @Override 246 public void invocationStarted(IInvocationContext context) { 247 myContext = context; 248 } 249 @Override 250 public void testRunEnded(long elapsedTimeMillis, HashMap<String, Metric> runMetrics) { 251 receivedComponentsTestRunEnded.addAll(myContext.getModuleInvocationContext() 252 .getConfigurationDescriptor().getMetaData("component")); 253 receivedModuleNameTestRunEnded.addAll(myContext.getModuleInvocationContext() 254 .getAttributes().get(IModuleDef.MODULE_NAME)); 255 receivedAbiTestRunEnded.addAll(myContext.getModuleInvocationContext() 256 .getAttributes().get(IModuleDef.MODULE_ABI)); 257 } 258 @Override 259 public void testEnded(TestDescription test, long endTime, 260 HashMap<String, Metric> testMetrics) { 261 receivedComponentsTestEnded.addAll(myContext.getModuleInvocationContext() 262 .getConfigurationDescriptor().getMetaData("component")); 263 receivedModuleNameTestEnded.addAll(myContext.getModuleInvocationContext() 264 .getAttributes().get(IModuleDef.MODULE_NAME)); 265 receivedAbiTestEnded.addAll(myContext.getModuleInvocationContext() 266 .getAttributes().get(IModuleDef.MODULE_ABI)); 267 } 268 }; 269 myListener.invocationStarted(mContext); 270 mTest.run(myListener); 271 myListener.invocationEnded(500); 272 EasyMock.verify(mMockDevice, mMockBuildInfo); 273 // verify metadata was retrieved during testRunEnded callbacks 274 assertEquals("[testRunEnded] wrong number of metadata collected", 275 1, receivedComponentsTestRunEnded.size()); 276 assertEquals("[testRunEnded] wrong component metadata field received", 277 component, receivedComponentsTestRunEnded.get(0)); 278 assertEquals("[testRunEnded] wrong number of module name collected", 279 1, receivedModuleNameTestRunEnded.size()); 280 assertEquals(moduleName, receivedModuleNameTestRunEnded.get(0)); 281 assertEquals("[testEnded] wrong number of module abi collected", 282 1, receivedAbiTestRunEnded.size()); 283 assertEquals(mAbi, receivedAbiTestRunEnded.get(0)); 284 // verify metadata was retrieved during testEnded callbacks 285 assertEquals("[testEnded] wrong number of metadata collected", 286 1, receivedComponentsTestEnded.size()); 287 assertEquals("[testEnded] wrong component metadata field received", 288 component, receivedComponentsTestEnded.get(0)); 289 assertEquals("[testEnded] wrong number of module name collected", 290 1, receivedModuleNameTestEnded.size()); 291 assertEquals(moduleName, receivedModuleNameTestEnded.get(0)); 292 assertEquals("[testEnded] wrong number of module abi collected", 293 1, receivedAbiTestEnded.size()); 294 assertEquals(mAbi, receivedAbiTestEnded.get(0)); 295 } 296 297 /** 298 * Simple tests running in one module that run some tests but not all of them. 299 */ 300 @Test testSingleModuleRun_incomplete()301 public void testSingleModuleRun_incomplete() throws Exception { 302 final String moduleName = "module_run_incomplete"; 303 final String mAbi = "arm64-v8a"; 304 createConfig(mTestDir, moduleName, TEST_STUB, true, false, true, false); 305 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 306 307 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 308 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 309 EasyMock.expectLastCall(); 310 311 EasyMock.replay(mMockDevice, mMockBuildInfo); 312 mReporter.invocationStarted(mContext); 313 mTest.run(mReporter); 314 mReporter.invocationEnded(500); 315 EasyMock.verify(mMockDevice, mMockBuildInfo); 316 IInvocationResult result = mReporter.getResult(); 317 assertEquals(1, result.countResults(TestStatus.PASS)); 318 assertEquals(1, result.countResults(TestStatus.FAIL)); 319 // Module should not be seen as complete. 320 assertEquals(1, result.getModules().size()); 321 assertEquals(0, result.getModuleCompleteCount()); 322 } 323 324 /** 325 * Simple tests running in one module that should be marked complete since it runs all its 326 * tests after an internal retry (like InstrumentationTest). 327 * FIXME: Fix the expectation of this test 328 */ 329 @Test testSingleModuleRun_completeAfterInternalRetry()330 public void testSingleModuleRun_completeAfterInternalRetry() throws Exception { 331 final String moduleName = "module_completeAfterRetry"; 332 final String mAbi = "arm64-v8a"; 333 createConfig(mTestDir, moduleName, TEST_STUB, true, true, true, true); 334 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 335 336 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 337 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 338 EasyMock.expectLastCall(); 339 340 EasyMock.replay(mMockDevice, mMockBuildInfo); 341 mReporter.invocationStarted(mContext); 342 mTest.run(mReporter); 343 mReporter.invocationEnded(500); 344 EasyMock.verify(mMockDevice, mMockBuildInfo); 345 IInvocationResult result = mReporter.getResult(); 346 // FIXME: All tests should be marked as executed and not aggregating the count. 347 assertEquals(2, result.countResults(TestStatus.PASS)); 348 assertEquals(1, result.countResults(TestStatus.FAIL)); 349 // FIXME: Module should be complete since all its test have run. 350 assertEquals(1, result.getModules().size()); 351 assertEquals(0, result.getModuleCompleteCount()); 352 } 353 354 /** 355 * Simple tests running in one module that run some tests but not all of them, then we 356 * attempt to run it again and they still didn't run. 357 * FIXME: This test expectation needs to be fixed 358 */ 359 @Test testSingleModuleRun_incomplete_rerun_incomplete()360 public void testSingleModuleRun_incomplete_rerun_incomplete() throws Exception { 361 final String moduleName = "module_incomplete_rerun"; 362 final String mAbi = "arm64-v8a"; 363 createConfig(mTestDir, moduleName, TEST_STUB, true, false, true, false); 364 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 365 366 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 367 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 368 EasyMock.expectLastCall(); 369 370 // extra calls for retry 371 EasyMock.expect(mMockDevice.getProperty("ro.build.fingerprint")).andReturn("fingerprint"); 372 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 373 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 374 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 375 EasyMock.expectLastCall(); 376 mMockBuildInfo.addBuildAttribute(EasyMock.eq("retry_command_line_args"), 377 EasyMock.eq(COMMAND_LINE)); 378 EasyMock.expectLastCall(); 379 380 EasyMock.replay(mMockDevice, mMockBuildInfo); 381 mReporter.invocationStarted(mContext); 382 mTest.run(mReporter); 383 mReporter.invocationEnded(500); 384 385 IInvocationResult result = mReporter.getResult(); 386 assertEquals(1, result.countResults(TestStatus.PASS)); 387 assertEquals(1, result.countResults(TestStatus.FAIL)); 388 // Module should not be seen as complete. 389 assertEquals(0, result.getModuleCompleteCount()); 390 391 // We re-run it 392 mReporter = new ResultReporter(); 393 mTest = new CompatibilityTest() { 394 @Override 395 protected Set<String> getAbisForBuildTargetArch() { 396 Set<String> abis = new HashSet<>(); 397 abis.add("arm64-v8a"); 398 return abis; 399 } 400 }; 401 mTest.setDevice(mMockDevice); 402 mTest.setBuild(mMockBuildInfo); 403 mTest.setInvocationContext(mContext); 404 OptionSetter setter = new OptionSetter(mTest, mReporter); 405 setter.setOptionValue("retry", "0"); 406 407 mReporter.invocationStarted(mContext); 408 mTest.run(mReporter); 409 mReporter.invocationEnded(500); 410 EasyMock.verify(mMockDevice, mMockBuildInfo); 411 412 // Check retry results 413 result = mReporter.getResult(); 414 // FIXME: We should only have 1 not_executed in the retry too. They should not aggregate 415 // from one run to another. 416 assertEquals(1, result.countResults(TestStatus.PASS)); 417 assertEquals(1, result.countResults(TestStatus.FAIL)); 418 // Module should not be seen as complete. 419 assertEquals(1, result.getModules().size()); 420 assertEquals(0, result.getModuleCompleteCount()); 421 } 422 423 /** 424 * Simple tests running in one module that run some tests but not all of them, we then attempt 425 * to retry run them and this time the not_executed is executed. 426 */ 427 @Test testSingleModuleRun_incomplete_rerun_complete()428 public void testSingleModuleRun_incomplete_rerun_complete() throws Exception { 429 final String moduleName = "module_incom_rerun_complete"; 430 final String mAbi = "arm64-v8a"; 431 createConfig(mTestDir, moduleName, TEST_STUB, true, false, true, false); 432 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 433 434 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 435 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 436 EasyMock.expectLastCall(); 437 438 // extra calls for retry 439 EasyMock.expect(mMockDevice.getProperty("ro.build.fingerprint")).andReturn("fingerprint"); 440 EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(mAbi); 441 mMockBuildInfo.addBuildAttribute(EasyMock.eq(CompatibilityBuildHelper.MODULE_IDS), 442 EasyMock.eq(AbiUtils.createId(mAbi, moduleName))); 443 EasyMock.expectLastCall(); 444 mMockBuildInfo.addBuildAttribute(EasyMock.eq("retry_command_line_args"), 445 EasyMock.eq(COMMAND_LINE)); 446 EasyMock.expectLastCall(); 447 448 EasyMock.replay(mMockDevice, mMockBuildInfo); 449 mReporter.invocationStarted(mContext); 450 mTest.run(mReporter); 451 mReporter.invocationEnded(500); 452 453 IInvocationResult result = mReporter.getResult(); 454 assertEquals(1, result.countResults(TestStatus.PASS)); 455 assertEquals(1, result.countResults(TestStatus.FAIL)); 456 // Module should not be seen as complete. 457 assertEquals(0, result.getModuleCompleteCount()); 458 459 // We replace the config by one that runs all tests without failures. 460 createConfig(mTestDir, moduleName, TEST_STUB, true, true, false, false); 461 // Usually configs do not change during the same session so we clear the map to have 462 // the new version of the config. 463 ((ConfigurationFactory)ConfigurationFactory.getInstance()).clearMapConfig(); 464 465 // We re-run it 466 mReporter = new ResultReporter(); 467 mTest = new CompatibilityTest() { 468 @Override 469 protected Set<String> getAbisForBuildTargetArch() { 470 Set<String> abis = new HashSet<>(); 471 abis.add("arm64-v8a"); 472 return abis; 473 } 474 }; 475 mTest.setDevice(mMockDevice); 476 mTest.setBuild(mMockBuildInfo); 477 mTest.setInvocationContext(mContext); 478 OptionSetter setter = new OptionSetter(mTest, mReporter); 479 setter.setOptionValue("retry", "0"); 480 481 mReporter.invocationStarted(mContext); 482 mTest.run(mReporter); 483 mReporter.invocationEnded(500); 484 EasyMock.verify(mMockDevice, mMockBuildInfo); 485 486 // Check retry results 487 result = mReporter.getResult(); 488 assertEquals(3, result.countResults(TestStatus.PASS)); 489 assertEquals(0, result.countResults(TestStatus.FAIL)); 490 // Module should be marked as complete after retry. 491 assertEquals(1, result.getModules().size()); 492 assertEquals(1, result.getModuleCompleteCount()); 493 } 494 495 // ***** Case for sharding interaction ***** 496 497 /** 498 * Helper to create a shard listener with the original reporter as master. 499 */ getShardListener(ResultReporter masterReporter)500 private ITestInvocationListener getShardListener(ResultReporter masterReporter) { 501 List<ITestInvocationListener> shardListeners = new ArrayList<ITestInvocationListener>(); 502 ShardListener origConfigListener = new ShardListener(masterReporter); 503 ResultReporter reporterClone = (ResultReporter) masterReporter.clone(); 504 shardListeners.add(reporterClone); 505 shardListeners.add(origConfigListener); 506 ResultForwarder shard = new ResultForwarder(shardListeners); 507 return shard; 508 } 509 510 /** 511 * Helper Thread to run the IShardableTest. 512 */ 513 private class ShardThread extends Thread { 514 private IRemoteTest mShardTest; 515 private ResultReporter mMasterReporter; 516 private IBuildInfo mBuild; 517 private ITestDevice mDevice; 518 private IInvocationContext mShardContext; 519 ShardThread(IRemoteTest test, ResultReporter masterReporter, IBuildInfo build, ITestDevice device, IInvocationContext context)520 public ShardThread(IRemoteTest test, ResultReporter masterReporter, IBuildInfo build, 521 ITestDevice device, IInvocationContext context) { 522 mShardTest = test; 523 mMasterReporter = masterReporter; 524 mBuild = build; 525 mDevice = device; 526 mShardContext = context; 527 } 528 529 @Override run()530 public void run() { 531 ITestInvocationListener listener = getShardListener(mMasterReporter); 532 ((IBuildReceiver)mShardTest).setBuild(mBuild); 533 ((IDeviceTest)mShardTest).setDevice(mDevice); 534 ((IInvocationContextReceiver)mShardTest).setInvocationContext(mContext); 535 listener.invocationStarted(mShardContext); 536 try { 537 mShardTest.run(listener); 538 } catch (DeviceNotAvailableException e) { 539 throw new RuntimeException(e); 540 } finally { 541 listener.invocationEnded(500); 542 } 543 } 544 } 545 } 546