Home | History | Annotate | Download | only in invoker
      1 /*
      2  * Copyright (C) 2010 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.invoker;
     17 
     18 import static org.mockito.Mockito.doReturn;
     19 
     20 import com.android.ddmlib.IDevice;
     21 import com.android.tradefed.build.BuildInfo;
     22 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
     23 import com.android.tradefed.build.BuildRetrievalError;
     24 import com.android.tradefed.build.IBuildInfo;
     25 import com.android.tradefed.build.IBuildInfo.BuildInfoProperties;
     26 import com.android.tradefed.build.IBuildProvider;
     27 import com.android.tradefed.build.IDeviceBuildInfo;
     28 import com.android.tradefed.build.IDeviceBuildProvider;
     29 import com.android.tradefed.command.CommandOptions;
     30 import com.android.tradefed.command.CommandRunner.ExitCode;
     31 import com.android.tradefed.command.FatalHostError;
     32 import com.android.tradefed.command.ICommandOptions;
     33 import com.android.tradefed.command.remote.DeviceDescriptor;
     34 import com.android.tradefed.config.Configuration;
     35 import com.android.tradefed.config.ConfigurationDef;
     36 import com.android.tradefed.config.DeviceConfigurationHolder;
     37 import com.android.tradefed.config.IConfiguration;
     38 import com.android.tradefed.config.IConfigurationFactory;
     39 import com.android.tradefed.config.IDeviceConfiguration;
     40 import com.android.tradefed.config.Option;
     41 import com.android.tradefed.config.OptionSetter;
     42 import com.android.tradefed.device.DeviceAllocationState;
     43 import com.android.tradefed.device.DeviceNotAvailableException;
     44 import com.android.tradefed.device.IDeviceRecovery;
     45 import com.android.tradefed.device.INativeDevice;
     46 import com.android.tradefed.device.ITestDevice;
     47 import com.android.tradefed.device.ITestDevice.RecoveryMode;
     48 import com.android.tradefed.device.StubDevice;
     49 import com.android.tradefed.device.TestDeviceOptions;
     50 import com.android.tradefed.device.metric.BaseDeviceMetricCollector;
     51 import com.android.tradefed.device.metric.DeviceMetricData;
     52 import com.android.tradefed.device.metric.IMetricCollector;
     53 import com.android.tradefed.guice.InvocationScope;
     54 import com.android.tradefed.invoker.shard.IShardHelper;
     55 import com.android.tradefed.invoker.shard.ShardHelper;
     56 import com.android.tradefed.invoker.shard.StrictShardHelper;
     57 import com.android.tradefed.log.ILeveledLogOutput;
     58 import com.android.tradefed.log.ILogRegistry;
     59 import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements;
     60 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
     61 import com.android.tradefed.result.ByteArrayInputStreamSource;
     62 import com.android.tradefed.result.ILogSaver;
     63 import com.android.tradefed.result.ILogSaverListener;
     64 import com.android.tradefed.result.ITestInvocationListener;
     65 import com.android.tradefed.result.ITestSummaryListener;
     66 import com.android.tradefed.result.InputStreamSource;
     67 import com.android.tradefed.result.InvocationStatus;
     68 import com.android.tradefed.result.LogDataType;
     69 import com.android.tradefed.result.LogFile;
     70 import com.android.tradefed.result.TestDescription;
     71 import com.android.tradefed.result.TestSummary;
     72 import com.android.tradefed.targetprep.BuildError;
     73 import com.android.tradefed.targetprep.ITargetCleaner;
     74 import com.android.tradefed.targetprep.ITargetPreparer;
     75 import com.android.tradefed.testtype.IDeviceTest;
     76 import com.android.tradefed.testtype.IInvocationContextReceiver;
     77 import com.android.tradefed.testtype.IRemoteTest;
     78 import com.android.tradefed.testtype.IResumableTest;
     79 import com.android.tradefed.testtype.IRetriableTest;
     80 import com.android.tradefed.testtype.IShardableTest;
     81 import com.android.tradefed.testtype.IStrictShardableTest;
     82 import com.android.tradefed.testtype.StubTest;
     83 import com.android.tradefed.util.FileUtil;
     84 import com.android.tradefed.util.SystemUtil.EnvVariable;
     85 
     86 import com.google.common.util.concurrent.SettableFuture;
     87 
     88 import junit.framework.Test;
     89 import junit.framework.TestCase;
     90 
     91 import org.easymock.Capture;
     92 import org.easymock.EasyMock;
     93 import org.mockito.Mockito;
     94 
     95 import java.io.File;
     96 import java.io.IOException;
     97 import java.io.InputStream;
     98 import java.util.ArrayList;
     99 import java.util.Collections;
    100 import java.util.HashMap;
    101 import java.util.HashSet;
    102 import java.util.List;
    103 import java.util.Map;
    104 import java.util.Set;
    105 
    106 /** Unit tests for {@link TestInvocation}. */
    107 @SuppressWarnings("MustBeClosedChecker")
    108 public class TestInvocationTest extends TestCase {
    109 
    110     private static final String SERIAL = "serial";
    111     private static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
    112     private static final String PATH = "path";
    113     private static final String URL = "url";
    114     private static final TestSummary mSummary = new TestSummary("http://www.url.com/report.txt");
    115     private static final InputStreamSource EMPTY_STREAM_SOURCE =
    116             new ByteArrayInputStreamSource(new byte[0]);
    117     private static final String LOGCAT_NAME_ERROR =
    118             TestInvocation.getDeviceLogName(TestInvocation.Stage.ERROR);
    119     private static final String LOGCAT_NAME_SETUP =
    120             TestInvocation.getDeviceLogName(TestInvocation.Stage.SETUP);
    121     private static final String LOGCAT_NAME_TEST =
    122             TestInvocation.getDeviceLogName(TestInvocation.Stage.TEST);
    123     private static final String LOGCAT_NAME_TEARDOWN =
    124             TestInvocation.getDeviceLogName(TestInvocation.Stage.TEARDOWN);
    125     /** The {@link TestInvocation} under test, with all dependencies mocked out */
    126     private TestInvocation mTestInvocation;
    127 
    128     private IConfiguration mStubConfiguration;
    129     private IConfiguration mStubMultiConfiguration;
    130 
    131     private IInvocationContext mStubInvocationMetadata;
    132 
    133     // The mock objects.
    134     private ITestDevice mMockDevice;
    135     private ITargetPreparer mMockPreparer;
    136     private IBuildProvider mMockBuildProvider;
    137     private IBuildInfo mMockBuildInfo;
    138     private ITestInvocationListener mMockTestListener;
    139     private ITestSummaryListener mMockSummaryListener;
    140     private ILeveledLogOutput mMockLogger;
    141     private ILogSaver mMockLogSaver;
    142     private IDeviceRecovery mMockRecovery;
    143     private Capture<List<TestSummary>> mUriCapture;
    144     private ILogRegistry mMockLogRegistry;
    145     private IConfigurationFactory mMockConfigFactory;
    146     private IRescheduler mockRescheduler;
    147     private DeviceDescriptor mFakeDescriptor;
    148 
    149     @Override
    150     protected void setUp() throws Exception {
    151         super.setUp();
    152 
    153         mStubConfiguration = new Configuration("foo", "bar");
    154         mStubMultiConfiguration = new Configuration("foo", "bar");
    155 
    156         mMockDevice = EasyMock.createMock(ITestDevice.class);
    157         mMockRecovery = EasyMock.createMock(IDeviceRecovery.class);
    158         mMockPreparer = EasyMock.createMock(ITargetPreparer.class);
    159         mMockBuildProvider = EasyMock.createMock(IBuildProvider.class);
    160 
    161         // Use strict mocks here since the order of Listener calls is important
    162         mMockTestListener = EasyMock.createStrictMock(ITestInvocationListener.class);
    163         mMockSummaryListener = EasyMock.createStrictMock(ITestSummaryListener.class);
    164         mMockBuildInfo = EasyMock.createMock(IBuildInfo.class);
    165         mMockLogger = EasyMock.createMock(ILeveledLogOutput.class);
    166         mMockLogRegistry = EasyMock.createMock(ILogRegistry.class);
    167         mMockLogSaver = EasyMock.createMock(ILogSaver.class);
    168         mMockConfigFactory = EasyMock.createMock(IConfigurationFactory.class);
    169         mockRescheduler = EasyMock.createMock(IRescheduler.class);
    170 
    171         mStubConfiguration.setDeviceRecovery(mMockRecovery);
    172         mStubConfiguration.setTargetPreparer(mMockPreparer);
    173         mStubConfiguration.setBuildProvider(mMockBuildProvider);
    174 
    175         EasyMock.expect(mMockPreparer.isDisabled()).andStubReturn(false);
    176         EasyMock.expect(mMockPreparer.isTearDownDisabled()).andStubReturn(false);
    177 
    178         List<IDeviceConfiguration> deviceConfigs = new ArrayList<IDeviceConfiguration>();
    179         IDeviceConfiguration device1 =
    180                 new DeviceConfigurationHolder(ConfigurationDef.DEFAULT_DEVICE_NAME);
    181         device1.addSpecificConfig(mMockRecovery);
    182         device1.addSpecificConfig(mMockPreparer);
    183         device1.addSpecificConfig(mMockBuildProvider);
    184         deviceConfigs.add(device1);
    185         mStubMultiConfiguration.setDeviceConfigList(deviceConfigs);
    186 
    187         mStubConfiguration.setLogSaver(mMockLogSaver);
    188         mStubMultiConfiguration.setLogSaver(mMockLogSaver);
    189 
    190         List<ITestInvocationListener> listenerList = new ArrayList<ITestInvocationListener>(1);
    191         listenerList.add(mMockTestListener);
    192         listenerList.add(mMockSummaryListener);
    193         mStubConfiguration.setTestInvocationListeners(listenerList);
    194         mStubMultiConfiguration.setTestInvocationListeners(listenerList);
    195 
    196         mStubConfiguration.setLogOutput(mMockLogger);
    197         mStubMultiConfiguration.setLogOutput(mMockLogger);
    198         EasyMock.expect(mMockDevice.getSerialNumber()).andStubReturn(SERIAL);
    199         EasyMock.expect(mMockDevice.getIDevice()).andStubReturn(null);
    200         mMockDevice.setRecovery(mMockRecovery);
    201         mMockDevice.preInvocationSetup((IBuildInfo)EasyMock.anyObject());
    202         EasyMock.expectLastCall().anyTimes();
    203         mMockDevice.postInvocationTearDown();
    204         EasyMock.expectLastCall().anyTimes();
    205         mFakeDescriptor = new DeviceDescriptor(SERIAL, false, DeviceAllocationState.Available,
    206                 "unknown", "unknown", "unknown", "unknown", "unknown");
    207         EasyMock.expect(mMockDevice.getDeviceDescriptor()).andStubReturn(mFakeDescriptor);
    208 
    209         EasyMock.expect(mMockBuildInfo.getBuildId()).andStubReturn("1");
    210         EasyMock.expect(mMockBuildInfo.getBuildAttributes()).andStubReturn(EMPTY_MAP);
    211         EasyMock.expect(mMockBuildInfo.getBuildBranch()).andStubReturn("branch");
    212         EasyMock.expect(mMockBuildInfo.getBuildFlavor()).andStubReturn("flavor");
    213         EasyMock.expect(mMockBuildInfo.getProperties()).andStubReturn(new HashSet<>());
    214 
    215         // always expect logger initialization and cleanup calls
    216         mMockLogRegistry.registerLogger(mMockLogger);
    217         mMockLogger.init();
    218         mMockLogger.closeLog();
    219         mMockLogRegistry.unregisterLogger();
    220         mUriCapture = new Capture<List<TestSummary>>();
    221 
    222         mStubInvocationMetadata = new InvocationContext();
    223         mStubInvocationMetadata.addAllocatedDevice(ConfigurationDef.DEFAULT_DEVICE_NAME,
    224                 mMockDevice);
    225         mStubInvocationMetadata.addDeviceBuildInfo(ConfigurationDef.DEFAULT_DEVICE_NAME,
    226                 mMockBuildInfo);
    227 
    228         // create the BaseTestInvocation to test
    229         mTestInvocation =
    230                 new TestInvocation() {
    231                     @Override
    232                     ILogRegistry getLogRegistry() {
    233                         return mMockLogRegistry;
    234                     }
    235 
    236                     @Override
    237                     public IInvocationExecution createInvocationExec(boolean isSandboxed) {
    238                         return new InvocationExecution() {
    239                             @Override
    240                             protected IShardHelper createShardHelper() {
    241                                 return new ShardHelper();
    242                             }
    243                         };
    244                     }
    245 
    246                     @Override
    247                     protected void setExitCode(ExitCode code, Throwable stack) {
    248                         // empty on purpose
    249                     }
    250 
    251                     @Override
    252                     InvocationScope getInvocationScope() {
    253                         // Avoid re-entry in the current TF invocation scope for unit tests.
    254                         return new InvocationScope();
    255                     }
    256                 };
    257     }
    258 
    259     @Override
    260     protected void tearDown() throws Exception {
    261       super.tearDown();
    262 
    263     }
    264 
    265     /**
    266      * Test the normal case invoke scenario with a {@link IRemoteTest}.
    267      * <p/>
    268      * Verifies that all external interfaces get notified as expected.
    269      */
    270     public void testInvoke_RemoteTest() throws Throwable {
    271         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    272         setupMockSuccessListeners();
    273 
    274         test.run((ITestInvocationListener)EasyMock.anyObject());
    275         setupNormalInvoke(test);
    276         EasyMock.replay(mockRescheduler);
    277         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    278         verifyMocks(test, mockRescheduler);
    279         verifySummaryListener();
    280     }
    281 
    282     /**
    283      * Test the normal case for multi invoke scenario with a {@link IRemoteTest}.
    284      * <p/>
    285      * Verifies that all external interfaces get notified as expected.
    286      */
    287     public void testInvokeMulti_RemoteTest() throws Throwable {
    288         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    289         setupMockSuccessListeners();
    290 
    291         test.run((ITestInvocationListener)EasyMock.anyObject());
    292         setupNormalInvoke(test);
    293         EasyMock.replay(mockRescheduler);
    294         mTestInvocation.invoke(mStubInvocationMetadata, mStubMultiConfiguration, mockRescheduler);
    295         verifyMocks(test, mockRescheduler);
    296         verifySummaryListener();
    297     }
    298 
    299     /**
    300      * Test the normal case invoke scenario with an {@link ITestSummaryListener} masquerading as
    301      * an {@link ITestInvocationListener}.
    302      * <p/>
    303      * Verifies that all external interfaces get notified as expected.
    304      */
    305     public void testInvoke_twoSummary() throws Throwable {
    306 
    307         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    308         setupMockSuccessListeners();
    309 
    310         test.run((ITestInvocationListener)EasyMock.anyObject());
    311         setupNormalInvoke(test);
    312         EasyMock.replay(mockRescheduler);
    313         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    314         verifyMocks(test, mockRescheduler);
    315         verifySummaryListener();
    316     }
    317 
    318     /**
    319      * Test the invoke scenario where build retrieve fails.
    320      * <p/>
    321      * An invocation will be started in this scenario.
    322      */
    323     public void testInvoke_buildFailed() throws Throwable  {
    324         BuildRetrievalError exception = new BuildRetrievalError("error", null, mMockBuildInfo);
    325         EasyMock.expect(mMockBuildProvider.getBuild()).andThrow(exception);
    326         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn(null);
    327         setupMockFailureListeners(exception);
    328         setupInvoke();
    329         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    330         CommandOptions cmdOptions = new CommandOptions();
    331         final String expectedTestTag = "TEST_TAG";
    332         cmdOptions.setTestTag(expectedTestTag);
    333         mStubConfiguration.setCommandOptions(cmdOptions);
    334         mStubConfiguration.setTest(test);
    335         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
    336         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(2);
    337         mMockDevice.clearLogcat();
    338         EasyMock.expectLastCall().times(2);
    339         mMockLogRegistry.unregisterLogger();
    340         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
    341         mMockLogger.closeLog();
    342         mMockBuildProvider.cleanUp(mMockBuildInfo);
    343         replayMocks(test, mockRescheduler);
    344         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    345         verifyMocks(test, mockRescheduler);
    346         // invocation test tag was updated.
    347         assertEquals(expectedTestTag, mStubInvocationMetadata.getTestTag());
    348     }
    349 
    350     /**
    351      * Test the invoke scenario where there is no build to test.
    352      */
    353     public void testInvoke_noBuild() throws Throwable  {
    354         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(null);
    355         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    356         mStubConfiguration.setTest(test);
    357         mMockBuildProvider.cleanUp(mMockBuildInfo);
    358         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
    359         setupInvoke();
    360         replayMocks(test, mockRescheduler);
    361         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    362         verifyMocks(test);
    363     }
    364 
    365     /**
    366      * Test the invoke scenario where there is no build to test for a {@link IRetriableTest}.
    367      */
    368     public void testInvoke_noBuildRetry() throws Throwable  {
    369         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(null);
    370 
    371         IRetriableTest test = EasyMock.createMock(IRetriableTest.class);
    372         EasyMock.expect(test.isRetriable()).andReturn(Boolean.TRUE);
    373 
    374         EasyMock.expect(mockRescheduler.rescheduleCommand()).andReturn(EasyMock.anyBoolean());
    375 
    376         mStubConfiguration.setTest(test);
    377         mStubConfiguration.getCommandOptions().setLoopMode(false);
    378         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
    379         EasyMock.expectLastCall().times(1);
    380         setupInvoke();
    381         mMockBuildProvider.cleanUp(mMockBuildInfo);
    382         replayMocks(test);
    383         EasyMock.replay(mockRescheduler);
    384         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    385         EasyMock.verify(mockRescheduler);
    386         verifyMocks(test);
    387     }
    388 
    389     /**
    390      * Test the{@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    391      * ITestInvocationListener[])} scenario
    392      * where the test is a {@link IDeviceTest}
    393      */
    394     public void testInvoke_deviceTest() throws Throwable {
    395          DeviceConfigTest mockDeviceTest = EasyMock.createMock(DeviceConfigTest.class);
    396          mStubConfiguration.setTest(mockDeviceTest);
    397          mockDeviceTest.setDevice(mMockDevice);
    398          mockDeviceTest.run((ITestInvocationListener)EasyMock.anyObject());
    399          setupMockSuccessListeners();
    400          setupNormalInvoke(mockDeviceTest);
    401          EasyMock.replay(mockRescheduler);
    402          mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    403          verifyMocks(mockDeviceTest, mockRescheduler);
    404          verifySummaryListener();
    405     }
    406 
    407     /**
    408      * Test the invoke scenario where test run throws {@link IllegalArgumentException}
    409      *
    410      * @throws Exception if unexpected error occurs
    411      */
    412     public void testInvoke_testFail() throws Throwable {
    413         IllegalArgumentException exception = new IllegalArgumentException();
    414         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    415         test.run((ITestInvocationListener)EasyMock.anyObject());
    416         EasyMock.expectLastCall().andThrow(exception);
    417         setupMockFailureListeners(exception);
    418         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    419         setupNormalInvoke(test);
    420         EasyMock.replay(mockRescheduler);
    421         try {
    422             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    423             fail("IllegalArgumentException was not rethrown");
    424         } catch (IllegalArgumentException e) {
    425             // expected
    426         }
    427         verifyMocks(test, mockRescheduler);
    428         verifySummaryListener();
    429     }
    430 
    431     /**
    432      * Test the invoke scenario where test run throws {@link FatalHostError}
    433      *
    434      * @throws Exception if unexpected error occurs
    435      */
    436     public void testInvoke_fatalError() throws Throwable {
    437         FatalHostError exception = new FatalHostError("error");
    438         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    439         test.run((ITestInvocationListener)EasyMock.anyObject());
    440         EasyMock.expectLastCall().andThrow(exception);
    441         setupMockFailureListeners(exception);
    442         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    443         setupNormalInvoke(test);
    444         EasyMock.replay(mockRescheduler);
    445         try {
    446             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    447             fail("FatalHostError was not rethrown");
    448         } catch (FatalHostError e)  {
    449             // expected
    450         }
    451         verifyMocks(test, mockRescheduler);
    452         verifySummaryListener();
    453     }
    454 
    455     /**
    456      * Test the invoke scenario where test run throws {@link DeviceNotAvailableException}
    457      *
    458      * @throws Exception if unexpected error occurs
    459      */
    460     public void testInvoke_deviceNotAvail() throws Throwable {
    461         DeviceNotAvailableException exception = new DeviceNotAvailableException("ERROR", SERIAL);
    462         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    463         test.run((ITestInvocationListener)EasyMock.anyObject());
    464         EasyMock.expectLastCall().andThrow(exception);
    465         mMockDevice.setRecoveryMode(RecoveryMode.NONE);
    466         EasyMock.expectLastCall();
    467         setupMockFailureListeners(exception);
    468         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    469         setupNormalInvoke(test);
    470         EasyMock.replay(mockRescheduler);
    471         try {
    472             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    473             fail("DeviceNotAvailableException not thrown");
    474         } catch (DeviceNotAvailableException e) {
    475             // expected
    476         }
    477         verifyMocks(test, mockRescheduler);
    478         verifySummaryListener();
    479     }
    480 
    481     /**
    482      * Test the invoke scenario where preparer throws {@link BuildError}
    483      *
    484      * @throws Exception if unexpected error occurs
    485      */
    486     public void testInvoke_buildError() throws Throwable {
    487         BuildError exception = new BuildError("error", mFakeDescriptor);
    488         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    489         mStubConfiguration.setTest(test);
    490         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
    491 
    492         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    493         EasyMock.expectLastCall().andThrow(exception);
    494         setupMockFailureListeners(exception);
    495         EasyMock.expect(mMockDevice.getBugreport()).andReturn(EMPTY_STREAM_SOURCE);
    496         setupInvokeWithBuild();
    497         replayMocks(test);
    498         EasyMock.replay(mockRescheduler);
    499         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    500         verifyMocks(test, mockRescheduler);
    501         verifySummaryListener();
    502     }
    503 
    504     /**
    505      * Test the invoke scenario for a {@link IResumableTest}.
    506      *
    507      * @throws Exception if unexpected error occurs
    508      */
    509     public void testInvoke_resume() throws Throwable {
    510         IResumableTest resumableTest = EasyMock.createMock(IResumableTest.class);
    511         mStubConfiguration.setTest(resumableTest);
    512         ITestInvocationListener resumeListener = EasyMock.createStrictMock(
    513                 ITestInvocationListener.class);
    514         mStubConfiguration.setTestInvocationListener(resumeListener);
    515 
    516         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
    517         resumeListener.invocationStarted(mStubInvocationMetadata);
    518         mMockDevice.clearLastConnectedWifiNetwork();
    519         mMockDevice.setOptions((TestDeviceOptions)EasyMock.anyObject());
    520         mMockBuildInfo.setDeviceSerial(SERIAL);
    521         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn("");
    522         mMockDevice.startLogcat();
    523         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    524 
    525         resumableTest.run((ITestInvocationListener) EasyMock.anyObject());
    526         EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException("ERROR", SERIAL));
    527         EasyMock.expect(resumableTest.isResumable()).andReturn(Boolean.TRUE);
    528         mMockDevice.setRecoveryMode(RecoveryMode.NONE);
    529         EasyMock.expectLastCall();
    530         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
    531         mMockDevice.clearLogcat();
    532         EasyMock.expectLastCall().times(3);
    533         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
    534         EasyMock.expect(
    535                         mMockLogSaver.saveLogData(
    536                                 EasyMock.eq(LOGCAT_NAME_SETUP),
    537                                 EasyMock.eq(LogDataType.LOGCAT),
    538                                 (InputStream) EasyMock.anyObject()))
    539                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    540         EasyMock.expect(
    541                         mMockLogSaver.saveLogData(
    542                                 EasyMock.eq(LOGCAT_NAME_TEST),
    543                                 EasyMock.eq(LogDataType.LOGCAT),
    544                                 (InputStream) EasyMock.anyObject()))
    545                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    546         EasyMock.expect(
    547                         mMockLogSaver.saveLogData(
    548                                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    549                                 EasyMock.eq(LogDataType.LOGCAT),
    550                                 (InputStream) EasyMock.anyObject()))
    551                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    552         EasyMock.expect(
    553                         mMockLogSaver.saveLogData(
    554                                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    555                                 EasyMock.eq(LogDataType.TEXT),
    556                                 (InputStream) EasyMock.anyObject()))
    557                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    558         resumeListener.testLog(
    559                 EasyMock.eq(LOGCAT_NAME_SETUP),
    560                 EasyMock.eq(LogDataType.LOGCAT),
    561                 (InputStreamSource) EasyMock.anyObject());
    562         resumeListener.testLog(
    563                 EasyMock.eq(LOGCAT_NAME_TEST),
    564                 EasyMock.eq(LogDataType.LOGCAT),
    565                 (InputStreamSource) EasyMock.anyObject());
    566         resumeListener.testLog(
    567                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    568                 EasyMock.eq(LogDataType.LOGCAT),
    569                 (InputStreamSource) EasyMock.anyObject());
    570         resumeListener.testLog(EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    571                 EasyMock.eq(LogDataType.TEXT), (InputStreamSource)EasyMock.anyObject());
    572 
    573         // just return same build and logger for simplicity
    574         EasyMock.expect(mMockBuildInfo.clone()).andReturn(mMockBuildInfo);
    575         EasyMock.expect(mMockLogger.clone()).andReturn(mMockLogger);
    576         IRescheduler mockRescheduler = EasyMock.createMock(IRescheduler.class);
    577         Capture<IConfiguration> capturedConfig = new Capture<IConfiguration>();
    578         EasyMock.expect(mockRescheduler.scheduleConfig(EasyMock.capture(capturedConfig)))
    579                 .andReturn(Boolean.TRUE);
    580         // When resuming the original build provider is still going to handle the clean up.
    581         mMockBuildProvider.cleanUp(mMockBuildInfo);
    582         EasyMock.expectLastCall().times(4);
    583         mMockDevice.clearLastConnectedWifiNetwork();
    584         mMockDevice.stopLogcat();
    585 
    586         mMockLogger.init();
    587         mMockLogSaver.invocationStarted(mStubInvocationMetadata);
    588         // now set resumed invocation expectations
    589         mMockDevice.clearLastConnectedWifiNetwork();
    590         mMockDevice.setOptions((TestDeviceOptions)EasyMock.anyObject());
    591         mMockBuildInfo.setDeviceSerial(SERIAL);
    592         mMockBuildInfo.setTestTag(EasyMock.eq("stub"));
    593         EasyMock.expectLastCall().times(2);
    594         mMockDevice.startLogcat();
    595         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    596         mMockLogSaver.invocationStarted(mStubInvocationMetadata);
    597         mMockDevice.setRecovery(mMockRecovery);
    598         resumableTest.run((ITestInvocationListener)EasyMock.anyObject());
    599         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
    600         mMockDevice.clearLogcat();
    601         EasyMock.expectLastCall().times(3);
    602         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
    603         EasyMock.expect(
    604                         mMockLogSaver.saveLogData(
    605                                 EasyMock.eq(LOGCAT_NAME_SETUP),
    606                                 EasyMock.eq(LogDataType.LOGCAT),
    607                                 (InputStream) EasyMock.anyObject()))
    608                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    609         EasyMock.expect(
    610                         mMockLogSaver.saveLogData(
    611                                 EasyMock.eq(LOGCAT_NAME_TEST),
    612                                 EasyMock.eq(LogDataType.LOGCAT),
    613                                 (InputStream) EasyMock.anyObject()))
    614                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    615         EasyMock.expect(
    616                         mMockLogSaver.saveLogData(
    617                                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    618                                 EasyMock.eq(LogDataType.LOGCAT),
    619                                 (InputStream) EasyMock.anyObject()))
    620                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    621         EasyMock.expect(
    622                         mMockLogSaver.saveLogData(
    623                                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    624                                 EasyMock.eq(LogDataType.TEXT),
    625                                 (InputStream) EasyMock.anyObject()))
    626                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
    627         resumeListener.testLog(
    628                 EasyMock.eq(LOGCAT_NAME_SETUP),
    629                 EasyMock.eq(LogDataType.LOGCAT),
    630                 (InputStreamSource) EasyMock.anyObject());
    631         resumeListener.testLog(
    632                 EasyMock.eq(LOGCAT_NAME_TEST),
    633                 EasyMock.eq(LogDataType.LOGCAT),
    634                 (InputStreamSource) EasyMock.anyObject());
    635         resumeListener.testLog(
    636                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    637                 EasyMock.eq(LogDataType.LOGCAT),
    638                 (InputStreamSource) EasyMock.anyObject());
    639         resumeListener.testLog(
    640                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    641                 EasyMock.eq(LogDataType.TEXT),
    642                 (InputStreamSource) EasyMock.anyObject());
    643         resumeListener.invocationEnded(EasyMock.anyLong());
    644         mMockLogSaver.invocationEnded(EasyMock.anyLong());
    645         EasyMock.expect(resumeListener.getSummary()).andReturn(null);
    646         mMockLogger.closeLog();
    647         EasyMock.expectLastCall().times(3);
    648         mMockDevice.clearLastConnectedWifiNetwork();
    649         mMockDevice.stopLogcat();
    650         EasyMock.replay(mockRescheduler, resumeListener, resumableTest, mMockPreparer,
    651                 mMockBuildProvider, mMockLogger, mMockLogSaver, mMockDevice, mMockBuildInfo);
    652 
    653         try {
    654             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    655             fail("DeviceNotAvailableException not thrown");
    656         } catch (DeviceNotAvailableException e) {
    657             // expect
    658         }
    659         // now call again, and expect invocation to be resumed properly
    660         mTestInvocation.invoke(mStubInvocationMetadata, capturedConfig.getValue(), mockRescheduler);
    661 
    662         EasyMock.verify(mockRescheduler, resumeListener, resumableTest, mMockPreparer,
    663                 mMockBuildProvider, mMockLogger, mMockLogSaver, mMockDevice, mMockBuildInfo);
    664     }
    665 
    666     /**
    667      * Test the invoke scenario for a {@link IRetriableTest}.
    668      *
    669      * @throws Exception if unexpected error occurs
    670      */
    671     public void testInvoke_retry() throws Throwable {
    672         AssertionError exception = new AssertionError();
    673         IRetriableTest test = EasyMock.createMock(IRetriableTest.class);
    674         test.run((ITestInvocationListener)EasyMock.anyObject());
    675         EasyMock.expectLastCall().andThrow(exception);
    676         EasyMock.expect(test.isRetriable()).andReturn(Boolean.TRUE);
    677         mStubConfiguration.getCommandOptions().setLoopMode(false);
    678         IRescheduler mockRescheduler = EasyMock.createMock(IRescheduler.class);
    679         EasyMock.expect(mockRescheduler.rescheduleCommand()).andReturn(EasyMock.anyBoolean());
    680         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    681         setupMockFailureListeners(exception);
    682         setupNormalInvoke(test);
    683         EasyMock.replay(mockRescheduler);
    684         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    685         verifyMocks(test, mockRescheduler);
    686         verifySummaryListener();
    687     }
    688 
    689     /**
    690      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    691      * ITestInvocationListener[])} scenario
    692      * when a {@link ITargetCleaner} is part of the config.
    693      */
    694     public void testInvoke_tearDown() throws Throwable {
    695          IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
    696          ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
    697         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
    698         EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
    699          mockCleaner.setUp(mMockDevice, mMockBuildInfo);
    700          mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
    701          mStubConfiguration.getTargetPreparers().add(mockCleaner);
    702          setupMockSuccessListeners();
    703          setupNormalInvoke(test);
    704          EasyMock.replay(mockCleaner, mockRescheduler);
    705          mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    706          verifyMocks(mockCleaner, mockRescheduler);
    707          verifySummaryListener();
    708     }
    709 
    710     /**
    711      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    712      * ITestInvocationListener[])} scenario
    713      * when a {@link ITargetCleaner} is part of the config, and the test throws a
    714      * {@link DeviceNotAvailableException}.
    715      */
    716     public void testInvoke_tearDown_deviceNotAvail() throws Throwable {
    717         DeviceNotAvailableException exception = new DeviceNotAvailableException("ERROR", SERIAL);
    718         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    719         test.run((ITestInvocationListener)EasyMock.anyObject());
    720         EasyMock.expectLastCall().andThrow(exception);
    721         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
    722         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
    723         EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
    724         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
    725         EasyMock.expectLastCall();
    726         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, exception);
    727         EasyMock.expectLastCall();
    728         mMockDevice.setRecoveryMode(RecoveryMode.NONE);
    729         EasyMock.expectLastCall();
    730         EasyMock.replay(mockCleaner, mockRescheduler);
    731         mStubConfiguration.getTargetPreparers().add(mockCleaner);
    732         setupMockFailureListeners(exception);
    733         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    734         setupNormalInvoke(test);
    735         try {
    736             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    737             fail("DeviceNotAvailableException not thrown");
    738         } catch (DeviceNotAvailableException e) {
    739             // expected
    740         }
    741         verifyMocks(mockCleaner, mockRescheduler);
    742         verifySummaryListener();
    743     }
    744 
    745     /**
    746      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    747      * ITestInvocationListener[])} scenario
    748      * when a {@link ITargetCleaner} is part of the config, and the test throws a
    749      * {@link RuntimeException}.
    750      */
    751     public void testInvoke_tearDown_runtime() throws Throwable {
    752         RuntimeException exception = new RuntimeException();
    753         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    754         test.run((ITestInvocationListener)EasyMock.anyObject());
    755         EasyMock.expectLastCall().andThrow(exception);
    756         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
    757         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
    758         EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
    759         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
    760         // tearDown should be called
    761         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, exception);
    762         mStubConfiguration.getTargetPreparers().add(mockCleaner);
    763         setupMockFailureListeners(exception);
    764         mMockBuildProvider.buildNotTested(mMockBuildInfo);
    765         setupNormalInvoke(test);
    766         EasyMock.replay(mockCleaner, mockRescheduler);
    767         try {
    768             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    769             fail("RuntimeException not thrown");
    770         } catch (RuntimeException e) {
    771             // expected
    772         }
    773         verifyMocks(mockCleaner, mockRescheduler);
    774         verifySummaryListener();
    775     }
    776 
    777     /**
    778      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    779      * ITestInvocationListener[])} scenario
    780      * when there is {@link ITestInvocationListener} which implements the {@link ILogSaverListener}
    781      * interface.
    782      */
    783     public void testInvoke_logFileSaved() throws Throwable {
    784         List<ITestInvocationListener> listenerList =
    785                 mStubConfiguration.getTestInvocationListeners();
    786         ILogSaverListener logSaverListener = EasyMock.createMock(ILogSaverListener.class);
    787         listenerList.add(logSaverListener);
    788         mStubConfiguration.setTestInvocationListeners(listenerList);
    789 
    790         logSaverListener.setLogSaver(mMockLogSaver);
    791         logSaverListener.invocationStarted(mStubInvocationMetadata);
    792         logSaverListener.testLog(
    793                 EasyMock.eq(LOGCAT_NAME_SETUP),
    794                 EasyMock.eq(LogDataType.LOGCAT),
    795                 (InputStreamSource) EasyMock.anyObject());
    796         logSaverListener.testLogSaved(
    797                 EasyMock.eq(LOGCAT_NAME_SETUP),
    798                 EasyMock.eq(LogDataType.LOGCAT),
    799                 (InputStreamSource) EasyMock.anyObject(),
    800                 (LogFile) EasyMock.anyObject());
    801         logSaverListener.logAssociation(EasyMock.eq(LOGCAT_NAME_SETUP), EasyMock.anyObject());
    802         logSaverListener.testLog(
    803                 EasyMock.eq(LOGCAT_NAME_TEST),
    804                 EasyMock.eq(LogDataType.LOGCAT),
    805                 (InputStreamSource) EasyMock.anyObject());
    806         logSaverListener.testLogSaved(
    807                 EasyMock.eq(LOGCAT_NAME_TEST),
    808                 EasyMock.eq(LogDataType.LOGCAT),
    809                 (InputStreamSource) EasyMock.anyObject(),
    810                 (LogFile) EasyMock.anyObject());
    811         logSaverListener.logAssociation(EasyMock.eq(LOGCAT_NAME_TEST), EasyMock.anyObject());
    812         logSaverListener.testLog(
    813                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    814                 EasyMock.eq(LogDataType.LOGCAT),
    815                 (InputStreamSource) EasyMock.anyObject());
    816         logSaverListener.testLogSaved(
    817                 EasyMock.eq(LOGCAT_NAME_TEARDOWN),
    818                 EasyMock.eq(LogDataType.LOGCAT),
    819                 (InputStreamSource) EasyMock.anyObject(),
    820                 (LogFile) EasyMock.anyObject());
    821         logSaverListener.logAssociation(EasyMock.eq(LOGCAT_NAME_TEARDOWN), EasyMock.anyObject());
    822         logSaverListener.testLog(
    823                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    824                 EasyMock.eq(LogDataType.TEXT),
    825                 (InputStreamSource) EasyMock.anyObject());
    826         logSaverListener.testLogSaved(
    827                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
    828                 EasyMock.eq(LogDataType.TEXT),
    829                 (InputStreamSource) EasyMock.anyObject(),
    830                 (LogFile) EasyMock.anyObject());
    831         logSaverListener.logAssociation(
    832                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME), EasyMock.anyObject());
    833         logSaverListener.invocationEnded(EasyMock.anyLong());
    834         EasyMock.expect(logSaverListener.getSummary()).andReturn(mSummary);
    835 
    836         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    837         setupMockSuccessListeners();
    838         test.run((ITestInvocationListener)EasyMock.anyObject());
    839         setupNormalInvoke(test);
    840         EasyMock.replay(logSaverListener, mockRescheduler);
    841         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    842         verifyMocks(test, logSaverListener, mockRescheduler);
    843         assertEquals(2, mUriCapture.getValue().size());
    844     }
    845 
    846     /**
    847      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    848      * ITestInvocationListener[])}
    849      * scenario with {@link IStrictShardableTest} when a shard index is given.
    850      */
    851     public void testInvoke_strictShardableTest_withShardIndex() throws Throwable {
    852         mTestInvocation =
    853                 new TestInvocation() {
    854                     @Override
    855                     ILogRegistry getLogRegistry() {
    856                         return mMockLogRegistry;
    857                     }
    858 
    859                     @Override
    860                     public IInvocationExecution createInvocationExec(boolean isSandboxed) {
    861                         return new InvocationExecution() {
    862                             @Override
    863                             protected IShardHelper createShardHelper() {
    864                                 return new StrictShardHelper();
    865                             }
    866                         };
    867                     }
    868 
    869                     @Override
    870                     protected void setExitCode(ExitCode code, Throwable stack) {
    871                         // empty on purpose
    872                     }
    873 
    874                     @Override
    875                     InvocationScope getInvocationScope() {
    876                         // Avoid re-entry in the current TF invocation scope for unit tests.
    877                         return new InvocationScope();
    878                     }
    879                 };
    880         String[] commandLine = {"config", "arg"};
    881         int shardCount = 10;
    882         int shardIndex = 5;
    883         IStrictShardableTest test = EasyMock.createMock(IStrictShardableTest.class);
    884         IRemoteTest testShard = EasyMock.createMock(IRemoteTest.class);
    885         mStubConfiguration.setTest(test);
    886         mStubConfiguration.setCommandLine(commandLine);
    887         mStubConfiguration.getCommandOptions().setShardCount(shardCount);
    888         mStubConfiguration.getCommandOptions().setShardIndex(shardIndex);
    889 
    890         setupInvokeWithBuild();
    891         setupMockSuccessListeners();
    892         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
    893         mMockBuildInfo.addBuildAttribute("command_line_args", "config arg");
    894         mMockBuildInfo.addBuildAttribute("shard_count", "10");
    895         mMockBuildInfo.addBuildAttribute("shard_index", "5");
    896         EasyMock.expect(test.getTestShard(shardCount, shardIndex)).andReturn(testShard);
    897         testShard.run((ITestInvocationListener)EasyMock.anyObject());
    898         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    899         replayMocks(test, testShard);
    900 
    901         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    902 
    903         verifyMocks(test, testShard);
    904     }
    905 
    906     /**
    907      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    908      * ITestInvocationListener[])}
    909      * scenario with non-{@link IStrictShardableTest} when shard index 0 is given.
    910      */
    911     public void testInvoke_nonStrictShardableTest_withShardIndexZero() throws Throwable {
    912         String[] commandLine = {"config", "arg"};
    913         int shardCount = 10;
    914         int shardIndex = 0;
    915         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    916         mStubConfiguration.setTest(test);
    917         mStubConfiguration.setCommandLine(commandLine);
    918         mStubConfiguration.getCommandOptions().setShardCount(shardCount);
    919         mStubConfiguration.getCommandOptions().setShardIndex(shardIndex);
    920 
    921         setupInvokeWithBuild();
    922         setupMockSuccessListeners();
    923         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
    924         mMockBuildInfo.addBuildAttribute("command_line_args", "config arg");
    925         mMockBuildInfo.addBuildAttribute("shard_count", "10");
    926         mMockBuildInfo.addBuildAttribute("shard_index", "0");
    927         test.run((ITestInvocationListener)EasyMock.anyObject());
    928         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    929         replayMocks(test);
    930 
    931         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    932 
    933         verifyMocks(test);
    934     }
    935 
    936     /**
    937      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
    938      * ITestInvocationListener[])}
    939      * scenario with non-{@link IStrictShardableTest} when a shard index non-0 is given.
    940      */
    941     public void testInvoke_nonStrictShardableTest_withShardIndexNonZero() throws Throwable {
    942         mTestInvocation =
    943                 new TestInvocation() {
    944                     @Override
    945                     ILogRegistry getLogRegistry() {
    946                         return mMockLogRegistry;
    947                     }
    948 
    949                     @Override
    950                     public IInvocationExecution createInvocationExec(boolean isSandboxed) {
    951                         return new InvocationExecution() {
    952                             @Override
    953                             protected IShardHelper createShardHelper() {
    954                                 return new StrictShardHelper();
    955                             }
    956                         };
    957                     }
    958 
    959                     @Override
    960                     protected void setExitCode(ExitCode code, Throwable stack) {
    961                         // empty on purpose
    962                     }
    963 
    964                     @Override
    965                     InvocationScope getInvocationScope() {
    966                         // Avoid re-entry in the current TF invocation scope for unit tests.
    967                         return new InvocationScope();
    968                     }
    969                 };
    970         String[] commandLine = {"config", "arg"};
    971         int shardCount = 10;
    972         int shardIndex = 1;
    973         IStrictShardableTest shardableTest = EasyMock.createMock(IStrictShardableTest.class);
    974         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
    975         EasyMock.expect(shardableTest.getTestShard(10, 1)).andReturn(test);
    976         test.run((ITestInvocationListener)EasyMock.anyObject());
    977         EasyMock.expectLastCall();
    978         mStubConfiguration.setTest(shardableTest);
    979         mStubConfiguration.setCommandLine(commandLine);
    980         mStubConfiguration.getCommandOptions().setShardCount(shardCount);
    981         mStubConfiguration.getCommandOptions().setShardIndex(shardIndex);
    982 
    983         setupInvokeWithBuild();
    984         setupMockSuccessListeners();
    985         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
    986         mMockBuildInfo.addBuildAttribute("command_line_args", "config arg");
    987         mMockBuildInfo.addBuildAttribute("shard_count", "10");
    988         mMockBuildInfo.addBuildAttribute("shard_index", "1");
    989         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
    990         replayMocks(shardableTest, test);
    991 
    992         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
    993 
    994         verifyMocks(shardableTest, test);
    995     }
    996 
    997     /**
    998      * Test the test-tag is set when the IBuildInfo's test-tag is not.
    999      */
   1000     public void testInvoke_testtag() throws Throwable {
   1001         String[] commandLine = {"run", "empty"};
   1002         mStubConfiguration.setCommandLine(commandLine);
   1003         mStubConfiguration.getCommandOptions().setTestTag("not-default");
   1004 
   1005         setupInvoke();
   1006         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
   1007         mMockDevice.clearLogcat();
   1008         EasyMock.expectLastCall().times(3);
   1009         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
   1010         mMockBuildInfo.setDeviceSerial(SERIAL);
   1011         mMockBuildProvider.cleanUp(mMockBuildInfo);
   1012         EasyMock.expectLastCall().times(2);
   1013         setupMockSuccessListeners();
   1014         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
   1015         mMockBuildInfo.addBuildAttribute("command_line_args", "run empty");
   1016         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
   1017         // Default build is "stub" so we set the test-tag
   1018         mMockBuildInfo.setTestTag(EasyMock.eq("not-default"));
   1019         EasyMock.expectLastCall();
   1020         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn("stub");
   1021         mMockLogRegistry.unregisterLogger();
   1022         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1023         mMockLogger.closeLog();
   1024         replayMocks();
   1025         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1026         verifyMocks();
   1027     }
   1028 
   1029     /**
   1030      * Test the test-tag of the IBuildInfo is not modified when the CommandOption default test-tag
   1031      * is not modified.
   1032      */
   1033     public void testInvoke_testtag_notset() throws Throwable {
   1034         String[] commandLine = {"run", "empty"};
   1035         mStubConfiguration.setCommandLine(commandLine);
   1036         setupInvoke();
   1037         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
   1038         mMockDevice.clearLogcat();
   1039         EasyMock.expectLastCall().times(3);
   1040         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
   1041         mMockBuildInfo.setDeviceSerial(SERIAL);
   1042         mMockBuildProvider.cleanUp(mMockBuildInfo);
   1043         EasyMock.expectLastCall().times(2);
   1044         setupMockSuccessListeners();
   1045         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
   1046         mMockBuildInfo.addBuildAttribute("command_line_args", "run empty");
   1047         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
   1048         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn("buildprovidertesttag");
   1049         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1050         mMockLogRegistry.unregisterLogger();
   1051         mMockLogger.closeLog();
   1052         replayMocks();
   1053         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1054         verifyMocks();
   1055     }
   1056 
   1057     /**
   1058      * Test the test-tag of the IBuildInfo is not set and Command Option is not set either.
   1059      * A default 'stub' test-tag is set to ensure reporting is done.
   1060      */
   1061     public void testInvoke_notesttag() throws Throwable {
   1062         String[] commandLine = {"run", "empty"};
   1063         mStubConfiguration.setCommandLine(commandLine);
   1064         setupInvoke();
   1065         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
   1066         mMockDevice.clearLogcat();
   1067         EasyMock.expectLastCall().times(3);
   1068         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
   1069         mMockBuildInfo.setDeviceSerial(SERIAL);
   1070         mMockBuildProvider.cleanUp(mMockBuildInfo);
   1071         EasyMock.expectLastCall().times(2);
   1072         setupMockSuccessListeners();
   1073         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
   1074         mMockBuildInfo.addBuildAttribute("command_line_args", "run empty");
   1075         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
   1076         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn(null);
   1077         mMockBuildInfo.setTestTag(EasyMock.eq("stub"));
   1078         EasyMock.expectLastCall();
   1079         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1080         mMockLogRegistry.unregisterLogger();
   1081         mMockLogger.closeLog();
   1082         replayMocks();
   1083         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1084         verifyMocks();
   1085     }
   1086 
   1087     /**
   1088      * Helper tests class to expose all the interfaces needed for the tests.
   1089      */
   1090     private interface IFakeBuildProvider extends IDeviceBuildProvider, IInvocationContextReceiver {
   1091     }
   1092 
   1093     /**
   1094      * Test the injection of test-tag from TestInvocation to the build provider via the
   1095      * {@link IInvocationContextReceiver}.
   1096      */
   1097     public void testInvoke_buildProviderNeedTestTag() throws Throwable {
   1098         final String testTag = "THISISTHETAG";
   1099         String[] commandLine = {"run", "empty"};
   1100         mStubConfiguration.setCommandLine(commandLine);
   1101         ICommandOptions commandOption = new CommandOptions();
   1102         commandOption.setTestTag(testTag);
   1103         IFakeBuildProvider mockProvider = EasyMock.createMock(IFakeBuildProvider.class);
   1104         mStubConfiguration.setBuildProvider(mockProvider);
   1105         mStubConfiguration.setCommandOptions(commandOption);
   1106         setupInvoke();
   1107         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
   1108         mMockDevice.clearLogcat();
   1109         EasyMock.expectLastCall().times(3);
   1110         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
   1111         mMockBuildInfo.setDeviceSerial(SERIAL);
   1112         setupMockSuccessListeners();
   1113         mMockBuildInfo.addBuildAttribute("command_line_args", "run empty");
   1114         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
   1115         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn(null);
   1116         // Validate proper tag is set on the build.
   1117         mMockBuildInfo.setTestTag(EasyMock.eq(testTag));
   1118         mockProvider.setInvocationContext((IInvocationContext)EasyMock.anyObject());
   1119         EasyMock.expect(mockProvider.getBuild(mMockDevice)).andReturn(mMockBuildInfo);
   1120         mockProvider.cleanUp(mMockBuildInfo);
   1121         EasyMock.expectLastCall().times(2);
   1122         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1123         mMockLogRegistry.unregisterLogger();
   1124         mMockLogger.closeLog();
   1125 
   1126         replayMocks(mockProvider);
   1127         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1128         verifyMocks(mockProvider);
   1129     }
   1130 
   1131     /**
   1132      * Set up expected conditions for normal run up to the part where tests are run.
   1133      *
   1134      * @param test the {@link Test} to use.
   1135      */
   1136     private void setupNormalInvoke(IRemoteTest test) throws Throwable {
   1137         setupInvokeWithBuild();
   1138         mStubConfiguration.setTest(test);
   1139         mStubMultiConfiguration.setTest(test);
   1140         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
   1141 
   1142         mMockPreparer.setUp(mMockDevice, mMockBuildInfo);
   1143         replayMocks(test);
   1144     }
   1145 
   1146     /**
   1147      * Set up expected calls that occur on every invoke, regardless of result
   1148      */
   1149     private void setupInvoke() {
   1150         mMockDevice.clearLastConnectedWifiNetwork();
   1151         mMockDevice.setOptions((TestDeviceOptions)EasyMock.anyObject());
   1152         mMockDevice.startLogcat();
   1153         mMockDevice.clearLastConnectedWifiNetwork();
   1154         mMockDevice.stopLogcat();
   1155     }
   1156 
   1157     /**
   1158      * Set up expected calls that occur on every invoke that gets a valid build
   1159      */
   1160     private void setupInvokeWithBuild() {
   1161         setupInvoke();
   1162         EasyMock.expect(mMockDevice.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(3);
   1163         mMockDevice.clearLogcat();
   1164         EasyMock.expectLastCall().times(3);
   1165 
   1166         EasyMock.expect(mMockLogger.getLog()).andReturn(EMPTY_STREAM_SOURCE);
   1167         mMockBuildInfo.setDeviceSerial(SERIAL);
   1168         mMockBuildProvider.cleanUp(mMockBuildInfo);
   1169         EasyMock.expectLastCall().anyTimes();
   1170         mMockBuildInfo.setTestTag(EasyMock.eq("stub"));
   1171         EasyMock.expectLastCall();
   1172         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn("");
   1173 
   1174         mMockLogRegistry.unregisterLogger();
   1175         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1176         mMockLogger.closeLog();
   1177     }
   1178 
   1179     /**
   1180      * Set up expected conditions for the test InvocationListener and SummaryListener
   1181      *
   1182      * <p>The order of calls for a single listener should be:
   1183      *
   1184      * <ol>
   1185      *   <li>invocationStarted
   1186      *   <li>testLog(LOGCAT_NAME_SETUP, ...) (if no build or retrieval error)
   1187      *   <li>invocationFailed (if run failed)
   1188      *   <li>testLog(LOGCAT_NAME_ERROR, ...) (if build retrieval error)
   1189      *   <li>testLog(LOGCAT_NAME_TEST, ...) (otherwise)
   1190      *   <li>testLog(build error bugreport, ...) (otherwise and if build error)
   1191      *   <li>testLog(LOGCAT_NAME_TEARDOWN, ...) (otherwise)
   1192      *   <li>testLog(TRADEFED_LOG_NAME, ...)
   1193      *   <li>putSummary (for an ITestSummaryListener)
   1194      *   <li>invocationEnded
   1195      *   <li>getSummary (for an ITestInvocationListener)
   1196      * </ol>
   1197      *
   1198      * However note that, across all listeners, any getSummary call will precede all putSummary
   1199      * calls.
   1200      */
   1201     private void setupMockListeners(InvocationStatus status, Throwable throwable)
   1202             throws IOException {
   1203         // invocationStarted
   1204         mMockLogSaver.invocationStarted(mStubInvocationMetadata);
   1205         mMockTestListener.invocationStarted(mStubInvocationMetadata);
   1206         mMockSummaryListener.invocationStarted(mStubInvocationMetadata);
   1207 
   1208         if (!(throwable instanceof BuildRetrievalError)) {
   1209             EasyMock.expect(
   1210                             mMockLogSaver.saveLogData(
   1211                                     EasyMock.eq(LOGCAT_NAME_SETUP),
   1212                                     EasyMock.eq(LogDataType.LOGCAT),
   1213                                     (InputStream) EasyMock.anyObject()))
   1214                     .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
   1215             mMockTestListener.testLog(
   1216                     EasyMock.eq(LOGCAT_NAME_SETUP),
   1217                     EasyMock.eq(LogDataType.LOGCAT),
   1218                     (InputStreamSource) EasyMock.anyObject());
   1219             mMockSummaryListener.testLog(
   1220                     EasyMock.eq(LOGCAT_NAME_SETUP),
   1221                     EasyMock.eq(LogDataType.LOGCAT),
   1222                     (InputStreamSource) EasyMock.anyObject());
   1223         }
   1224 
   1225         // invocationFailed
   1226         if (!status.equals(InvocationStatus.SUCCESS)) {
   1227             mMockTestListener.invocationFailed(EasyMock.eq(throwable));
   1228             mMockSummaryListener.invocationFailed(EasyMock.eq(throwable));
   1229         }
   1230 
   1231         if (throwable instanceof BuildRetrievalError) {
   1232             // Handle logcat error listeners
   1233             EasyMock.expect(
   1234                             mMockLogSaver.saveLogData(
   1235                                     EasyMock.eq(LOGCAT_NAME_ERROR),
   1236                                     EasyMock.eq(LogDataType.LOGCAT),
   1237                                     (InputStream) EasyMock.anyObject()))
   1238                     .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
   1239             mMockTestListener.testLog(
   1240                     EasyMock.eq(LOGCAT_NAME_ERROR),
   1241                     EasyMock.eq(LogDataType.LOGCAT),
   1242                     (InputStreamSource) EasyMock.anyObject());
   1243             mMockSummaryListener.testLog(
   1244                     EasyMock.eq(LOGCAT_NAME_ERROR),
   1245                     EasyMock.eq(LogDataType.LOGCAT),
   1246                     (InputStreamSource) EasyMock.anyObject());
   1247         } else {
   1248             // Handle test logcat listeners
   1249             EasyMock.expect(
   1250                             mMockLogSaver.saveLogData(
   1251                                     EasyMock.eq(LOGCAT_NAME_TEST),
   1252                                     EasyMock.eq(LogDataType.LOGCAT),
   1253                                     (InputStream) EasyMock.anyObject()))
   1254                     .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
   1255             mMockTestListener.testLog(
   1256                     EasyMock.eq(LOGCAT_NAME_TEST),
   1257                     EasyMock.eq(LogDataType.LOGCAT),
   1258                     (InputStreamSource) EasyMock.anyObject());
   1259             mMockSummaryListener.testLog(
   1260                     EasyMock.eq(LOGCAT_NAME_TEST),
   1261                     EasyMock.eq(LogDataType.LOGCAT),
   1262                     (InputStreamSource) EasyMock.anyObject());
   1263             // Handle build error bugreport listeners
   1264             if (throwable instanceof BuildError) {
   1265                 EasyMock.expect(
   1266                                 mMockDevice.logBugreport(
   1267                                         EasyMock.eq(
   1268                                                 TestInvocation.BUILD_ERROR_BUGREPORT_NAME
   1269                                                         + "_"
   1270                                                         + SERIAL),
   1271                                         EasyMock.anyObject()))
   1272                         .andReturn(true);
   1273             }
   1274             // Handle teardown logcat listeners
   1275             EasyMock.expect(
   1276                             mMockLogSaver.saveLogData(
   1277                                     EasyMock.eq(LOGCAT_NAME_TEARDOWN),
   1278                                     EasyMock.eq(LogDataType.LOGCAT),
   1279                                     (InputStream) EasyMock.anyObject()))
   1280                     .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
   1281             mMockTestListener.testLog(
   1282                     EasyMock.eq(LOGCAT_NAME_TEARDOWN),
   1283                     EasyMock.eq(LogDataType.LOGCAT),
   1284                     (InputStreamSource) EasyMock.anyObject());
   1285             mMockSummaryListener.testLog(
   1286                     EasyMock.eq(LOGCAT_NAME_TEARDOWN),
   1287                     EasyMock.eq(LogDataType.LOGCAT),
   1288                     (InputStreamSource) EasyMock.anyObject());
   1289         }
   1290 
   1291         EasyMock.expect(
   1292                         mMockLogSaver.saveLogData(
   1293                                 EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
   1294                                 EasyMock.eq(LogDataType.TEXT),
   1295                                 (InputStream) EasyMock.anyObject()))
   1296                 .andReturn(new LogFile(PATH, URL, LogDataType.TEXT));
   1297         mMockTestListener.testLog(EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
   1298                 EasyMock.eq(LogDataType.TEXT), (InputStreamSource)EasyMock.anyObject());
   1299         mMockSummaryListener.testLog(EasyMock.eq(TestInvocation.TRADEFED_LOG_NAME),
   1300                 EasyMock.eq(LogDataType.TEXT), (InputStreamSource)EasyMock.anyObject());
   1301 
   1302         // invocationEnded, getSummary (mMockTestListener)
   1303         mMockTestListener.invocationEnded(EasyMock.anyLong());
   1304         EasyMock.expect(mMockTestListener.getSummary()).andReturn(mSummary);
   1305 
   1306         // putSummary, invocationEnded (mMockSummaryListener)
   1307         mMockSummaryListener.putSummary(EasyMock.capture(mUriCapture));
   1308         mMockSummaryListener.invocationEnded(EasyMock.anyLong());
   1309         mMockLogSaver.invocationEnded(EasyMock.anyLong());
   1310     }
   1311 
   1312     /**
   1313      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
   1314      * ITestInvocationListener[])} scenario with {@link IShardableTest}.
   1315      */
   1316     public void testInvoke_shardableTest_legacy() throws Throwable {
   1317         String command = "empty --test-tag t";
   1318         String[] commandLine = {"empty", "--test-tag", "t"};
   1319         int shardCount = 2;
   1320         IShardableTest test = EasyMock.createMock(IShardableTest.class);
   1321         List<IRemoteTest> shards = new ArrayList<>();
   1322         IRemoteTest shard1 = EasyMock.createMock(IRemoteTest.class);
   1323         IRemoteTest shard2 = EasyMock.createMock(IRemoteTest.class);
   1324         shards.add(shard1);
   1325         shards.add(shard2);
   1326         EasyMock.expect(test.split()).andReturn(shards);
   1327         mStubConfiguration.setTest(test);
   1328         mStubConfiguration.setCommandLine(commandLine);
   1329         mMockBuildProvider.cleanUp(mMockBuildInfo);
   1330         setupInvoke();
   1331         setupNShardInvocation(shardCount, command);
   1332         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
   1333         replayMocks(test, mockRescheduler, shard1, shard2);
   1334         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1335         verifyMocks(test, mockRescheduler, shard1, shard2);
   1336     }
   1337 
   1338     /**
   1339      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is not
   1340      * adding battery information for placeholder device.
   1341      */
   1342     public void testLogDeviceBatteryLevel_placeholderDevice() {
   1343         final String fakeEvent = "event";
   1344         IInvocationContext context = new InvocationContext();
   1345         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1346         EasyMock.expect(device1.getIDevice()).andReturn(new StubDevice("serial1"));
   1347         context.addAllocatedDevice("device1", device1);
   1348         EasyMock.replay(device1);
   1349         mTestInvocation.logDeviceBatteryLevel(context, fakeEvent);
   1350         EasyMock.verify(device1);
   1351         assertEquals(0, context.getAttributes().size());
   1352     }
   1353 
   1354     /**
   1355      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
   1356      * battery information for physical real device.
   1357      */
   1358     public void testLogDeviceBatteryLevel_physicalDevice() {
   1359         final String fakeEvent = "event";
   1360         IInvocationContext context = new InvocationContext();
   1361         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1362         IDevice idevice = Mockito.mock(IDevice.class);
   1363         EasyMock.expect(device1.getIDevice()).andReturn(idevice);
   1364         SettableFuture<Integer> future = SettableFuture.create();
   1365         future.set(50);
   1366         doReturn(future).when(idevice).getBattery(Mockito.anyLong(), Mockito.any());
   1367         EasyMock.expect(device1.getSerialNumber()).andReturn("serial1");
   1368         context.addAllocatedDevice("device1", device1);
   1369         context.addDeviceBuildInfo("device1", new BuildInfo());
   1370         EasyMock.replay(device1);
   1371         mTestInvocation.logDeviceBatteryLevel(context, fakeEvent);
   1372         EasyMock.verify(device1);
   1373         assertEquals(1, context.getBuildInfo("device1").getBuildAttributes().size());
   1374         assertEquals(
   1375                 "50",
   1376                 context.getBuildInfo("device1")
   1377                         .getBuildAttributes()
   1378                         .get("serial1-battery-" + fakeEvent));
   1379     }
   1380 
   1381     /**
   1382      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
   1383      * battery information for multiple physical real device.
   1384      */
   1385     public void testLogDeviceBatteryLevel_physicalDevice_multi() {
   1386         final String fakeEvent = "event";
   1387         IInvocationContext context = new InvocationContext();
   1388         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1389         IDevice idevice = Mockito.mock(IDevice.class);
   1390         EasyMock.expect(device1.getSerialNumber()).andReturn("serial1");
   1391         EasyMock.expect(device1.getIDevice()).andReturn(idevice);
   1392         SettableFuture<Integer> future = SettableFuture.create();
   1393         future.set(50);
   1394         doReturn(future).when(idevice).getBattery(Mockito.anyLong(), Mockito.any());
   1395         ITestDevice device2 = EasyMock.createMock(ITestDevice.class);
   1396         EasyMock.expect(device2.getIDevice()).andReturn(idevice);
   1397         EasyMock.expect(device2.getSerialNumber()).andReturn("serial2");
   1398         context.addAllocatedDevice("device1", device1);
   1399         context.addDeviceBuildInfo("device1", new BuildInfo());
   1400         context.addAllocatedDevice("device2", device2);
   1401         context.addDeviceBuildInfo("device2", new BuildInfo());
   1402         EasyMock.replay(device1, device2);
   1403         mTestInvocation.logDeviceBatteryLevel(context, fakeEvent);
   1404         EasyMock.verify(device1, device2);
   1405         assertEquals(1, context.getBuildInfo("device1").getBuildAttributes().size());
   1406         assertEquals(1, context.getBuildInfo("device2").getBuildAttributes().size());
   1407         assertEquals(
   1408                 "50",
   1409                 context.getBuildInfo("device1")
   1410                         .getBuildAttributes()
   1411                         .get("serial1-battery-" + fakeEvent));
   1412         assertEquals(
   1413                 "50",
   1414                 context.getBuildInfo("device2")
   1415                         .getBuildAttributes()
   1416                         .get("serial2-battery-" + fakeEvent));
   1417     }
   1418 
   1419     /**
   1420      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
   1421      * battery information for multiple physical real device, and ignore stub device if any.
   1422      */
   1423     public void testLogDeviceBatteryLevel_physicalDevice_stub_multi() {
   1424         final String fakeEvent = "event";
   1425         IInvocationContext context = new InvocationContext();
   1426         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1427         IDevice idevice = Mockito.mock(IDevice.class);
   1428         EasyMock.expect(device1.getSerialNumber()).andReturn("serial1");
   1429         EasyMock.expect(device1.getIDevice()).andReturn(idevice);
   1430         SettableFuture<Integer> future = SettableFuture.create();
   1431         future.set(50);
   1432         doReturn(future).when(idevice).getBattery(Mockito.anyLong(), Mockito.any());
   1433         ITestDevice device2 = EasyMock.createMock(ITestDevice.class);
   1434         EasyMock.expect(device2.getIDevice()).andReturn(idevice);
   1435         EasyMock.expect(device2.getSerialNumber()).andReturn("serial2");
   1436         ITestDevice device3 = EasyMock.createMock(ITestDevice.class);
   1437         EasyMock.expect(device1.getIDevice()).andStubReturn(new StubDevice("stub1"));
   1438         ITestDevice device4 = EasyMock.createMock(ITestDevice.class);
   1439         EasyMock.expect(device1.getIDevice()).andStubReturn(new StubDevice("stub2"));
   1440         context.addAllocatedDevice("device1", device1);
   1441         context.addDeviceBuildInfo("device1", new BuildInfo());
   1442         context.addAllocatedDevice("device2", device2);
   1443         context.addDeviceBuildInfo("device2", new BuildInfo());
   1444         context.addAllocatedDevice("device3", device3);
   1445         context.addAllocatedDevice("device4", device4);
   1446         EasyMock.replay(device1, device2);
   1447         mTestInvocation.logDeviceBatteryLevel(context, fakeEvent);
   1448         EasyMock.verify(device1, device2);
   1449         assertEquals(1, context.getBuildInfo("device1").getBuildAttributes().size());
   1450         assertEquals(1, context.getBuildInfo("device2").getBuildAttributes().size());
   1451         assertEquals(
   1452                 "50",
   1453                 context.getBuildInfo("device1")
   1454                         .getBuildAttributes()
   1455                         .get("serial1-battery-" + fakeEvent));
   1456         assertEquals(
   1457                 "50",
   1458                 context.getBuildInfo("device2")
   1459                         .getBuildAttributes()
   1460                         .get("serial2-battery-" + fakeEvent));
   1461     }
   1462 
   1463     /** Helper to set the expectation for N number of shards. */
   1464     private void setupNShardInvocation(int numShard, String commandLine) throws Exception {
   1465         mMockBuildInfo.setTestTag(EasyMock.eq("stub"));
   1466         EasyMock.expectLastCall();
   1467         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(mMockBuildInfo);
   1468         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn("");
   1469         mMockBuildInfo.addBuildAttribute("command_line_args", commandLine);
   1470         mMockTestListener.invocationStarted((IInvocationContext)EasyMock.anyObject());
   1471         EasyMock.expectLastCall();
   1472         mMockSummaryListener.invocationStarted((IInvocationContext)EasyMock.anyObject());
   1473         EasyMock.expectLastCall();
   1474         EasyMock.expect(mMockLogger.clone()).andReturn(mMockLogger).times(numShard);
   1475         EasyMock.expect(mMockBuildInfo.clone()).andReturn(mMockBuildInfo).times(numShard);
   1476         EasyMock.expect(mockRescheduler.scheduleConfig(EasyMock.anyObject()))
   1477                 .andReturn(true).times(numShard);
   1478         mMockBuildInfo.setDeviceSerial(SERIAL);
   1479         EasyMock.expectLastCall();
   1480         mMockBuildProvider.cleanUp(EasyMock.anyObject());
   1481         EasyMock.expectLastCall();
   1482     }
   1483 
   1484     private void setupMockSuccessListeners() throws IOException {
   1485         setupMockListeners(InvocationStatus.SUCCESS, null);
   1486     }
   1487 
   1488     private void setupMockFailureListeners(Throwable throwable) throws IOException {
   1489         setupMockListeners(InvocationStatus.FAILED, throwable);
   1490     }
   1491 
   1492     private void verifySummaryListener() {
   1493         // Check that we captured the expected uris List
   1494         List<TestSummary> summaries = mUriCapture.getValue();
   1495         assertEquals(1, summaries.size());
   1496         assertEquals(mSummary, summaries.get(0));
   1497     }
   1498 
   1499     /**
   1500      * Verify all mock objects received expected calls
   1501      */
   1502     private void verifyMocks(Object... mocks) {
   1503         // note: intentionally exclude configuration from verification - don't care
   1504         // what methods are called
   1505         EasyMock.verify(mMockTestListener, mMockSummaryListener, mMockPreparer,
   1506                 mMockBuildProvider, mMockLogger, mMockBuildInfo, mMockLogRegistry,
   1507                 mMockLogSaver);
   1508         if (mocks.length > 0) {
   1509             EasyMock.verify(mocks);
   1510         }
   1511     }
   1512 
   1513     /**
   1514      * Switch all mock objects into replay mode.
   1515      */
   1516     private void replayMocks(Object... mocks) {
   1517         EasyMock.replay(mMockTestListener, mMockSummaryListener, mMockPreparer,
   1518                 mMockBuildProvider, mMockLogger, mMockBuildInfo, mMockLogRegistry,
   1519                 mMockLogSaver, mMockDevice, mMockConfigFactory);
   1520         if (mocks.length > 0) {
   1521             EasyMock.replay(mocks);
   1522         }
   1523     }
   1524 
   1525     /**
   1526      * Interface for testing device config pass through.
   1527      */
   1528     private interface DeviceConfigTest extends IRemoteTest, IDeviceTest {
   1529 
   1530     }
   1531 
   1532     /**
   1533      * Test {@link INativeDevice#preInvocationSetup(IBuildInfo info)} is called when command option
   1534      * skip-pre-device-setup is not set.
   1535      */
   1536     public void testNotSkipPreDeviceSetup() throws Throwable {
   1537         IInvocationContext context = new InvocationContext();
   1538         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1539         IDevice idevice = Mockito.mock(IDevice.class);
   1540         context.addAllocatedDevice("DEFAULT_DEVICE", device1);
   1541         EasyMock.expect(device1.getSerialNumber()).andReturn("serial1").anyTimes();
   1542         EasyMock.expect(device1.getIDevice()).andReturn(idevice).anyTimes();
   1543         EasyMock.expect(device1.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(1);
   1544         device1.clearLogcat();
   1545         EasyMock.expectLastCall().once();
   1546         device1.preInvocationSetup((IBuildInfo) EasyMock.anyObject());
   1547         EasyMock.expectLastCall().once();
   1548 
   1549         CommandOptions commandOption = new CommandOptions();
   1550         OptionSetter setter = new OptionSetter(commandOption);
   1551         setter.setOptionValue("skip-pre-device-setup", "false");
   1552         mStubConfiguration.setCommandOptions(commandOption);
   1553 
   1554         EasyMock.expect(mMockPreparer.isDisabled()).andReturn(true);
   1555         // Not expect isTearDownDisabled.
   1556 
   1557         ITestInvocationListener listener = EasyMock.createStrictMock(ITestInvocationListener.class);
   1558         listener.testLog(
   1559                 EasyMock.eq(LOGCAT_NAME_SETUP),
   1560                 EasyMock.eq(LogDataType.LOGCAT),
   1561                 (InputStreamSource) EasyMock.anyObject());
   1562 
   1563         EasyMock.replay(device1, listener, mMockPreparer);
   1564         new InvocationExecution().doSetup(context, mStubConfiguration, listener);
   1565         EasyMock.verify(device1, listener, mMockPreparer);
   1566 
   1567     }
   1568 
   1569     /**
   1570      * Test {@link INativeDevice#preInvocationSetup(IBuildInfo info)} is not called when command
   1571      * option skip-pre-device-setup is set.
   1572      */
   1573     public void testSkipPreDeviceSetup() throws Throwable {
   1574         IInvocationContext context = new InvocationContext();
   1575         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
   1576         IDevice idevice = Mockito.mock(IDevice.class);
   1577         context.addAllocatedDevice("DEFAULT_DEVICE", device1);
   1578         EasyMock.expect(device1.getSerialNumber()).andReturn("serial1").anyTimes();
   1579         EasyMock.expect(device1.getIDevice()).andReturn(idevice).anyTimes();
   1580         EasyMock.expect(device1.getLogcat()).andReturn(EMPTY_STREAM_SOURCE).times(1);
   1581         device1.clearLogcat();
   1582         EasyMock.expectLastCall().once();
   1583 
   1584         CommandOptions commandOption = new CommandOptions();
   1585         OptionSetter setter = new OptionSetter(commandOption);
   1586         setter.setOptionValue("skip-pre-device-setup", "true");
   1587         mStubConfiguration.setCommandOptions(commandOption);
   1588 
   1589         EasyMock.expect(mMockPreparer.isDisabled()).andReturn(true);
   1590         // Not expect isTearDownDisabled
   1591 
   1592         ITestInvocationListener listener = EasyMock.createStrictMock(ITestInvocationListener.class);
   1593         listener.testLog(
   1594                 EasyMock.eq(LOGCAT_NAME_SETUP),
   1595                 EasyMock.eq(LogDataType.LOGCAT),
   1596                 (InputStreamSource) EasyMock.anyObject());
   1597 
   1598         EasyMock.replay(device1, listener, mMockPreparer);
   1599         new InvocationExecution().doSetup(context, mStubConfiguration, listener);
   1600         EasyMock.verify(device1, listener, mMockPreparer);
   1601     }
   1602 
   1603     /**
   1604      * Test when a {@link IDeviceBuildInfo} is passing through we do not attempt to add any external
   1605      * directories when there is none coming from environment.
   1606      */
   1607     public void testInvoke_deviceInfoBuild_noEnv() throws Throwable {
   1608         mTestInvocation =
   1609                 new TestInvocation() {
   1610                     @Override
   1611                     ILogRegistry getLogRegistry() {
   1612                         return mMockLogRegistry;
   1613                     }
   1614 
   1615                     @Override
   1616                     public IInvocationExecution createInvocationExec(boolean isSandboxed) {
   1617                         return new InvocationExecution() {
   1618                             @Override
   1619                             protected IShardHelper createShardHelper() {
   1620                                 return new ShardHelper();
   1621                             }
   1622 
   1623                             @Override
   1624                             File getExternalTestCasesDirs(EnvVariable envVar) {
   1625                                 // Return empty list to ensure we do not have any environment loaded
   1626                                 return null;
   1627                             }
   1628                         };
   1629                     }
   1630 
   1631                     @Override
   1632                     protected void setExitCode(ExitCode code, Throwable stack) {
   1633                         // empty on purpose
   1634                     }
   1635 
   1636                     @Override
   1637                     InvocationScope getInvocationScope() {
   1638                         // Avoid re-entry in the current TF invocation scope for unit tests.
   1639                         return new InvocationScope();
   1640                     }
   1641                 };
   1642         mMockBuildInfo = EasyMock.createMock(IDeviceBuildInfo.class);
   1643         EasyMock.expect(mMockBuildInfo.getProperties()).andStubReturn(new HashSet<>());
   1644         IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
   1645         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
   1646         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
   1647         EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
   1648         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
   1649         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
   1650         mStubConfiguration.getTargetPreparers().add(mockCleaner);
   1651 
   1652         File tmpTestsDir = FileUtil.createTempDir("invocation-tests-dir");
   1653         try {
   1654             EasyMock.expect(((IDeviceBuildInfo) mMockBuildInfo).getTestsDir())
   1655                     .andReturn(tmpTestsDir);
   1656             setupMockSuccessListeners();
   1657             setupNormalInvoke(test);
   1658             EasyMock.replay(mockCleaner, mockRescheduler);
   1659             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1660             verifyMocks(mockCleaner, mockRescheduler);
   1661             verifySummaryListener();
   1662         } finally {
   1663             FileUtil.recursiveDelete(tmpTestsDir);
   1664         }
   1665     }
   1666 
   1667     /**
   1668      * Test when a {@link IDeviceBuildInfo} is passing through we attempt to add the external
   1669      * directories to it when they are available.
   1670      */
   1671     public void testInvoke_deviceInfoBuild_withEnv() throws Throwable {
   1672         File tmpTestsDir = FileUtil.createTempDir("invocation-tests-dir");
   1673         File tmpExternalTestsDir = FileUtil.createTempDir("external-tf-dir");
   1674         File tmpTestsFile = FileUtil.createTempFile("testsfile", "txt", tmpExternalTestsDir);
   1675         try {
   1676             mTestInvocation =
   1677                     new TestInvocation() {
   1678                         @Override
   1679                         ILogRegistry getLogRegistry() {
   1680                             return mMockLogRegistry;
   1681                         }
   1682 
   1683                         @Override
   1684                         public IInvocationExecution createInvocationExec(boolean isSandboxed) {
   1685                             return new InvocationExecution() {
   1686                                 @Override
   1687                                 protected IShardHelper createShardHelper() {
   1688                                     return new ShardHelper();
   1689                                 }
   1690 
   1691                                 @Override
   1692                                 File getExternalTestCasesDirs(EnvVariable envVar) {
   1693                                     if (EnvVariable.ANDROID_TARGET_OUT_TESTCASES.equals(envVar)) {
   1694                                         return tmpExternalTestsDir;
   1695                                     }
   1696                                     return null;
   1697                                 }
   1698                             };
   1699                         }
   1700 
   1701                         @Override
   1702                         protected void setExitCode(ExitCode code, Throwable stack) {
   1703                             // empty on purpose
   1704                         }
   1705 
   1706                         @Override
   1707                         InvocationScope getInvocationScope() {
   1708                             // Avoid re-entry in the current TF invocation scope for unit tests.
   1709                             return new InvocationScope();
   1710                         }
   1711                     };
   1712             mMockBuildInfo = EasyMock.createMock(IDeviceBuildInfo.class);
   1713             IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
   1714             ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
   1715             EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
   1716             EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
   1717             mockCleaner.setUp(mMockDevice, mMockBuildInfo);
   1718             mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
   1719             mStubConfiguration.getTargetPreparers().add(mockCleaner);
   1720 
   1721             mMockBuildInfo.setFile(
   1722                     EasyMock.contains(BuildInfoFileKey.TARGET_LINKED_DIR.getFileKey()),
   1723                     EasyMock.anyObject(),
   1724                     EasyMock.eq("v1"));
   1725             EasyMock.expect(((IDeviceBuildInfo) mMockBuildInfo).getTestsDir())
   1726                     .andReturn(tmpTestsDir);
   1727             EasyMock.expect(mMockBuildInfo.getProperties()).andStubReturn(new HashSet<>());
   1728 
   1729             setupMockSuccessListeners();
   1730             setupNormalInvoke(test);
   1731             EasyMock.replay(mockCleaner, mockRescheduler);
   1732             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1733             verifyMocks(mockCleaner, mockRescheduler);
   1734             verifySummaryListener();
   1735             // Check that the external directory was copied in the testsDir.
   1736             assertTrue(tmpTestsDir.listFiles().length == 1);
   1737             // external-tf-dir - the symlink is the original file name + randomized sequence
   1738             assertTrue(
   1739                     tmpTestsDir
   1740                             .listFiles()[0]
   1741                             .getName()
   1742                             .startsWith(BuildInfoFileKey.TARGET_LINKED_DIR.getFileKey()));
   1743             // testsfile.txt
   1744             assertTrue(tmpTestsDir.listFiles()[0].listFiles().length == 1);
   1745             assertEquals(
   1746                     tmpTestsFile.getName(), tmpTestsDir.listFiles()[0].listFiles()[0].getName());
   1747         } finally {
   1748             FileUtil.recursiveDelete(tmpTestsDir);
   1749             FileUtil.recursiveDelete(tmpExternalTestsDir);
   1750         }
   1751     }
   1752 
   1753     /**
   1754      * Test when a {@link IDeviceBuildInfo} is passing through we do not attempt to add the external
   1755      * directories to it, since {@link BuildInfoProperties} is set to skip the linking.
   1756      */
   1757     public void testInvoke_deviceInfoBuild_withEnv_andSkipProperty() throws Throwable {
   1758         File tmpTestsDir = FileUtil.createTempDir("invocation-tests-dir");
   1759         File tmpExternalTestsDir = FileUtil.createTempDir("external-tf-dir");
   1760         FileUtil.createTempFile("testsfile", "txt", tmpExternalTestsDir);
   1761         try {
   1762             mTestInvocation =
   1763                     new TestInvocation() {
   1764                         @Override
   1765                         ILogRegistry getLogRegistry() {
   1766                             return mMockLogRegistry;
   1767                         }
   1768 
   1769                         @Override
   1770                         public IInvocationExecution createInvocationExec(boolean isSandboxed) {
   1771                             return new InvocationExecution() {
   1772                                 @Override
   1773                                 protected IShardHelper createShardHelper() {
   1774                                     return new ShardHelper();
   1775                                 }
   1776 
   1777                                 @Override
   1778                                 File getExternalTestCasesDirs(EnvVariable envVar) {
   1779                                     return tmpExternalTestsDir;
   1780                                 }
   1781                             };
   1782                         }
   1783 
   1784                         @Override
   1785                         protected void setExitCode(ExitCode code, Throwable stack) {
   1786                             // empty on purpose
   1787                         }
   1788 
   1789                         @Override
   1790                         InvocationScope getInvocationScope() {
   1791                             // Avoid re-entry in the current TF invocation scope for unit tests.
   1792                             return new InvocationScope();
   1793                         }
   1794                     };
   1795             mMockBuildInfo = EasyMock.createMock(IDeviceBuildInfo.class);
   1796             IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
   1797             ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
   1798             EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
   1799             EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
   1800             mockCleaner.setUp(mMockDevice, mMockBuildInfo);
   1801             mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
   1802             mStubConfiguration.getTargetPreparers().add(mockCleaner);
   1803 
   1804             Set<BuildInfoProperties> prop = new HashSet<>();
   1805             prop.add(BuildInfoProperties.DO_NOT_LINK_TESTS_DIR);
   1806             EasyMock.expect(mMockBuildInfo.getProperties()).andStubReturn(prop);
   1807 
   1808             setupMockSuccessListeners();
   1809             setupNormalInvoke(test);
   1810             EasyMock.replay(mockCleaner, mockRescheduler);
   1811             mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
   1812             verifyMocks(mockCleaner, mockRescheduler);
   1813             verifySummaryListener();
   1814             // Check that the external directory was NOT copied in the testsDir.
   1815             assertTrue(tmpTestsDir.listFiles().length == 0);
   1816         } finally {
   1817             FileUtil.recursiveDelete(tmpTestsDir);
   1818             FileUtil.recursiveDelete(tmpExternalTestsDir);
   1819         }
   1820     }
   1821 
   1822     public static class TestableCollector extends BaseDeviceMetricCollector {
   1823 
   1824         @Option(name = "name")
   1825         private String mName;
   1826 
   1827         public TestableCollector() {}
   1828 
   1829         public TestableCollector(String name) {
   1830             mName = name;
   1831         }
   1832 
   1833         @Override
   1834         public void onTestRunEnd(
   1835                 DeviceMetricData runData, final Map<String, Metric> currentRunMetrics) {
   1836             runData.addMetric(
   1837                     mName,
   1838                     Metric.newBuilder()
   1839                             .setMeasurements(
   1840                                     Measurements.newBuilder().setSingleString(mName).build()));
   1841         }
   1842     }
   1843 
   1844     /**
   1845      * Test that when {@link IMetricCollector} are used, they wrap and call in sequence the listener
   1846      * so all metrics end up on the final receiver.
   1847      */
   1848     public void testMetricCollectionChain() throws Exception {
   1849         IConfiguration configuration = new Configuration("test", "description");
   1850         StubTest test = new StubTest();
   1851         OptionSetter setter = new OptionSetter(test);
   1852         setter.setOptionValue("run-a-test", "true");
   1853         configuration.setTest(test);
   1854 
   1855         List<IMetricCollector> collectors = new ArrayList<>();
   1856         collectors.add(new TestableCollector("collector1"));
   1857         collectors.add(new TestableCollector("collector2"));
   1858         collectors.add(new TestableCollector("collector3"));
   1859         collectors.add(new TestableCollector("collector4"));
   1860         configuration.setDeviceMetricCollectors(collectors);
   1861 
   1862         mMockTestListener.testRunStarted("TestStub", 1);
   1863         TestDescription testId = new TestDescription("StubTest", "StubMethod");
   1864         mMockTestListener.testStarted(EasyMock.eq(testId), EasyMock.anyLong());
   1865         mMockTestListener.testEnded(
   1866                 EasyMock.eq(testId),
   1867                 EasyMock.anyLong(),
   1868                 EasyMock.eq(new HashMap<String, Metric>()));
   1869         Capture<HashMap<String, Metric>> captured = new Capture<>();
   1870         mMockTestListener.testRunEnded(EasyMock.anyLong(), EasyMock.capture(captured));
   1871         EasyMock.replay(mMockTestListener);
   1872         new InvocationExecution()
   1873                 .runTests(mStubInvocationMetadata, configuration, mMockTestListener);
   1874         EasyMock.verify(mMockTestListener);
   1875         // The collectors are called in sequence
   1876         List<String> listKeys = new ArrayList<>(captured.getValue().keySet());
   1877         assertEquals(4, listKeys.size());
   1878         assertEquals("collector4", listKeys.get(0));
   1879         assertEquals("collector3", listKeys.get(1));
   1880         assertEquals("collector2", listKeys.get(2));
   1881         assertEquals("collector1", listKeys.get(3));
   1882     }
   1883 }
   1884