Home | History | Annotate | Download | only in testtype
      1 /*
      2  * Copyright (C) 2016 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.testtype;
     17 
     18 import static com.google.common.truth.Truth.assertThat;
     19 import static org.mockito.AdditionalMatchers.gt;
     20 import static org.mockito.Mockito.any;
     21 import static org.mockito.Mockito.anyCollection;
     22 import static org.mockito.Mockito.anyInt;
     23 import static org.mockito.Mockito.anyString;
     24 import static org.mockito.Mockito.doAnswer;
     25 import static org.mockito.Mockito.doReturn;
     26 import static org.mockito.Mockito.eq;
     27 import static org.mockito.Mockito.mock;
     28 import static org.mockito.Mockito.verify;
     29 
     30 import com.android.ddmlib.IDevice;
     31 import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
     32 import com.android.ddmlib.testrunner.ITestRunListener;
     33 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
     34 import com.android.ddmlib.testrunner.TestIdentifier;
     35 import com.android.ddmlib.testrunner.TestRunResult;
     36 import com.android.tradefed.build.BuildInfo;
     37 import com.android.tradefed.build.IBuildInfo;
     38 import com.android.tradefed.device.DeviceNotAvailableException;
     39 import com.android.tradefed.device.ITestDevice;
     40 import com.android.tradefed.log.ITestLogger;
     41 import com.android.tradefed.result.InputStreamSource;
     42 import com.android.tradefed.result.ITestInvocationListener;
     43 import com.android.tradefed.result.LogDataType;
     44 import com.android.tradefed.util.ICompressionStrategy;
     45 import com.android.tradefed.util.ListInstrumentationParser;
     46 import com.android.tradefed.util.ListInstrumentationParser.InstrumentationTarget;
     47 
     48 import com.google.common.collect.ImmutableList;
     49 import com.google.common.collect.ImmutableMap;
     50 import com.google.common.collect.Lists;
     51 import com.google.protobuf.ByteString;
     52 
     53 import org.junit.Before;
     54 import org.junit.Rule;
     55 import org.junit.Test;
     56 import org.junit.rules.TemporaryFolder;
     57 import org.junit.runner.RunWith;
     58 import org.junit.runners.JUnit4;
     59 import org.mockito.Mock;
     60 import org.mockito.Mockito;
     61 import org.mockito.MockitoAnnotations;
     62 import org.mockito.invocation.InvocationOnMock;
     63 import org.mockito.stubbing.Answer;
     64 
     65 import java.io.File;
     66 import java.io.FileInputStream;
     67 import java.io.FileOutputStream;
     68 import java.io.InputStream;
     69 import java.io.IOException;
     70 import java.util.ArrayList;
     71 import java.util.Collection;
     72 import java.util.HashMap;
     73 import java.util.List;
     74 import java.util.Map;
     75 
     76 /** Unit tests for {@link CodeCoverageTestBase}. */
     77 @RunWith(JUnit4.class)
     78 public class CodeCoverageTestBaseTest {
     79 
     80     private static final long TEST_RUN_TIME = 1000;
     81     private static final String COVERAGE_PATH = "/data/user/0/%s/files/coverage.ec";
     82 
     83     private static final String PACKAGE_NAME1 = "com.example.foo.test";
     84     private static final String PACKAGE_NAME2 = "com.example.bar.test";
     85     private static final String PACKAGE_NAME3 = "com.example.baz.test";
     86 
     87     private static final String RUNNER_NAME1 = "android.support.test.runner.AndroidJUnitRunner";
     88     private static final String RUNNER_NAME2 = "android.test.InstrumentationTestRunner";
     89     private static final String RUNNER_NAME3 = "com.example.custom.Runner";
     90 
     91     private static final TestIdentifier FOO_TEST1 = new TestIdentifier(".FooTest", "test1");
     92     private static final TestIdentifier FOO_TEST2 = new TestIdentifier(".FooTest", "test2");
     93     private static final TestIdentifier FOO_TEST3 = new TestIdentifier(".FooTest", "test3");
     94     private static final List<TestIdentifier> FOO_TESTS =
     95             ImmutableList.of(FOO_TEST1, FOO_TEST2, FOO_TEST3);
     96 
     97     private static final TestIdentifier BAR_TEST1 = new TestIdentifier(".BarTest", "test1");
     98     private static final TestIdentifier BAR_TEST2 = new TestIdentifier(".BarTest", "test2");
     99     private static final List<TestIdentifier> BAR_TESTS = ImmutableList.of(BAR_TEST1, BAR_TEST2);
    100 
    101     private static final TestIdentifier BAZ_TEST1 = new TestIdentifier(".BazTest", "test1");
    102     private static final TestIdentifier BAZ_TEST2 = new TestIdentifier(".BazTest", "test2");
    103     private static final List<TestIdentifier> BAZ_TESTS = ImmutableList.of(BAZ_TEST1, BAZ_TEST2);
    104 
    105     private static final ByteString FAKE_REPORT_CONTENTS =
    106             ByteString.copyFromUtf8("Mi estas kovrado raporto");
    107 
    108     private static final ByteString FAKE_MEASUREMENT1 =
    109             ByteString.copyFromUtf8("Mi estas kovrado mezurado");
    110     private static final ByteString FAKE_MEASUREMENT2 =
    111             ByteString.copyFromUtf8("Mi estas ankau kovrado mezurado");
    112     private static final ByteString FAKE_MEASUREMENT3 =
    113             ByteString.copyFromUtf8("Mi estas ankorau alia priraportado mezurado");
    114 
    115     private static final IBuildInfo BUILD_INFO = new BuildInfo("123456", "device-userdebug");
    116 
    117     @Rule public TemporaryFolder mFolder = new TemporaryFolder();
    118 
    119     // Mocks
    120     @Mock ITestDevice mDevice;
    121 
    122     @Mock ITestInvocationListener mListener;
    123 
    124     @Mock ListInstrumentationParser mInstrumentationParser;
    125 
    126     // Fake test data
    127     @Mock TestDataRegistry<List<TestIdentifier>> mTests;
    128 
    129     @Mock TestDataRegistry<ByteString> mMeasurements;
    130 
    131     interface TestDataRegistry<T> {
    132         T get(String packageName, String runnerName, int shardIndex, int numShards);
    133     }
    134 
    135     /** Object under test */
    136     CodeCoverageTestStub mCoverageTest;
    137 
    138     @Before
    139     public void setUp() throws DeviceNotAvailableException {
    140         MockitoAnnotations.initMocks(this);
    141         doAnswer(CALL_RUNNER)
    142                 .when(mDevice)
    143                 .runInstrumentationTests(
    144                         any(IRemoteAndroidTestRunner.class), any(ITestRunListener.class));
    145         mCoverageTest = new CodeCoverageTestStub();
    146     }
    147 
    148     static enum FakeReportFormat implements CodeCoverageReportFormat {
    149         CSV(LogDataType.JACOCO_CSV),
    150         XML(LogDataType.JACOCO_XML),
    151         HTML(LogDataType.HTML);
    152 
    153         private LogDataType mLogDataType;
    154 
    155         private FakeReportFormat(LogDataType logDataType) {
    156             mLogDataType = logDataType;
    157         }
    158 
    159         @Override
    160         public LogDataType getLogDataType() { return mLogDataType; }
    161     }
    162 
    163     /** A subclass of {@link CodeCoverageTest} with certain methods stubbed out for testing. */
    164     private class CodeCoverageTestStub extends CodeCoverageTestBase<FakeReportFormat> {
    165 
    166         // Captured data
    167         private ImmutableList.Builder<ByteString> mCapturedMeasurements =
    168                 new ImmutableList.Builder<>();
    169 
    170         public CodeCoverageTestStub() {
    171             setDevice(mDevice);
    172         }
    173 
    174         @Override
    175         public IBuildInfo getBuild() { return BUILD_INFO; }
    176 
    177         @Override
    178         ICompressionStrategy getCompressionStrategy() {
    179             return mock(ICompressionStrategy.class);
    180         }
    181 
    182         ImmutableList<ByteString> getMeasurements() {
    183             return mCapturedMeasurements.build();
    184         }
    185 
    186         @Override
    187         protected File generateCoverageReport(
    188                 Collection<File> measurementFiles, FakeReportFormat format) throws IOException {
    189             // Capture the measurements for verification later
    190             for (File measurementFile : measurementFiles) {
    191                 try (FileInputStream inputStream = new FileInputStream(measurementFile)) {
    192                     mCapturedMeasurements.add(ByteString.readFrom(inputStream));
    193                 }
    194             }
    195 
    196             // Write the fake report
    197             File ret = mFolder.newFile();
    198             FAKE_REPORT_CONTENTS.writeTo(new FileOutputStream(ret));
    199             return ret;
    200         }
    201 
    202         @Override
    203         protected List<FakeReportFormat> getReportFormat() {
    204             return ImmutableList.of(FakeReportFormat.HTML);
    205         }
    206 
    207         @Override
    208         InstrumentationTest internalCreateTest() {
    209             return new InstrumentationTest() {
    210                 @Override
    211                 IRemoteAndroidTestRunner createRemoteAndroidTestRunner(
    212                         String packageName, String runnerName, IDevice device) {
    213                     return new FakeTestRunner(packageName, runnerName);
    214                 }
    215             };
    216         }
    217 
    218         @Override
    219         IRemoteAndroidTestRunner internalCreateTestRunner(String packageName, String runnerName) {
    220             return new FakeTestRunner(packageName, runnerName);
    221         }
    222 
    223         @Override
    224         ListInstrumentationParser internalCreateListInstrumentationParser() {
    225             return mInstrumentationParser;
    226         }
    227     }
    228 
    229     private static final class LogCaptorAnswer implements Answer<Void> {
    230         private ByteString mValue;
    231 
    232         @Override
    233         public Void answer(InvocationOnMock invocation) throws Throwable {
    234             Object[] args = invocation.getArguments();
    235             InputStream reportStream = ((InputStreamSource) args[2]).createInputStream();
    236             mValue = ByteString.readFrom(reportStream);
    237             return null;
    238         }
    239 
    240         ByteString getValue() {
    241             return mValue;
    242         }
    243     }
    244 
    245     @Test
    246     public void testRun() throws DeviceNotAvailableException, IOException {
    247         // Prepare some test data
    248         doReturn(ImmutableList.of(new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "")))
    249                 .when(mInstrumentationParser)
    250                 .getInstrumentationTargets();
    251 
    252         // Mocking boilerplate
    253         doReturn(FOO_TESTS)
    254                 .when(mTests)
    255                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    256         doReturn(FAKE_MEASUREMENT1)
    257                 .when(mMeasurements)
    258                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    259 
    260         // Validate the report when it gets log, since the file will get cleaned up later
    261         LogCaptorAnswer logCaptor = new LogCaptorAnswer();
    262         doAnswer(logCaptor)
    263                 .when(mListener)
    264                 .testLog(
    265                         eq("coverage"),
    266                         eq(FakeReportFormat.HTML.getLogDataType()),
    267                         any(InputStreamSource.class));
    268 
    269         // Run the test
    270         mCoverageTest.run(mListener);
    271 
    272         // Verify that the measurements were collected and the report was logged
    273         assertThat(mCoverageTest.getMeasurements()).containsExactly(FAKE_MEASUREMENT1);
    274         assertThat(logCaptor.getValue()).isEqualTo(FAKE_REPORT_CONTENTS);
    275     }
    276 
    277     @Test
    278     public void testRun_multipleInstrumentationTargets()
    279             throws DeviceNotAvailableException, IOException {
    280         // Prepare some test data
    281         ImmutableList<InstrumentationTarget> targets =
    282                 ImmutableList.of(
    283                         new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, ""),
    284                         new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME1, ""),
    285                         new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, ""));
    286         doReturn(targets).when(mInstrumentationParser).getInstrumentationTargets();
    287 
    288         // Mocking boilerplate
    289         doReturn(FOO_TESTS)
    290                 .when(mTests)
    291                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    292         doReturn(FAKE_MEASUREMENT1)
    293                 .when(mMeasurements)
    294                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    295 
    296         doReturn(BAR_TESTS)
    297                 .when(mTests)
    298                 .get(eq(PACKAGE_NAME2), eq(RUNNER_NAME1), anyInt(), anyInt());
    299         doReturn(FAKE_MEASUREMENT2)
    300                 .when(mMeasurements)
    301                 .get(eq(PACKAGE_NAME2), eq(RUNNER_NAME1), anyInt(), anyInt());
    302 
    303         doReturn(BAZ_TESTS)
    304                 .when(mTests)
    305                 .get(eq(PACKAGE_NAME3), eq(RUNNER_NAME1), anyInt(), anyInt());
    306         doReturn(FAKE_MEASUREMENT3)
    307                 .when(mMeasurements)
    308                 .get(eq(PACKAGE_NAME3), eq(RUNNER_NAME1), anyInt(), anyInt());
    309 
    310         // Run the test
    311         mCoverageTest.run(mListener);
    312 
    313         // Verify that all targets were run by checking that we recieved measurements from each
    314         assertThat(mCoverageTest.getMeasurements())
    315                 .containsExactly(FAKE_MEASUREMENT1, FAKE_MEASUREMENT2, FAKE_MEASUREMENT3);
    316     }
    317 
    318     @Test
    319     public void testRun_multipleShards() throws DeviceNotAvailableException {
    320         // Prepare some test data
    321         doReturn(ImmutableList.of(new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "")))
    322                 .when(mInstrumentationParser)
    323                 .getInstrumentationTargets();
    324         List<List<TestIdentifier>> shards = Lists.partition(FOO_TESTS, 1);
    325 
    326         // Indicate that the test should be split into 3 shards
    327         doReturn(FOO_TESTS).when(mTests).get(PACKAGE_NAME1, RUNNER_NAME1, 0, 1);
    328         doReturn(FOO_TESTS.subList(0, FOO_TESTS.size() / 2))
    329                 .when(mTests)
    330                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), eq(2));
    331         mCoverageTest.setMaxTestsPerChunk(1);
    332 
    333         // Return subsets of FOO_TESTS when running shards
    334         doReturn(shards.get(0)).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), gt(1));
    335         doReturn(FAKE_MEASUREMENT1)
    336                 .when(mMeasurements)
    337                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), gt(1));
    338 
    339         doReturn(shards.get(1)).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(1), gt(1));
    340         doReturn(FAKE_MEASUREMENT2)
    341                 .when(mMeasurements)
    342                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(1), gt(1));
    343 
    344         doReturn(shards.get(2)).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(2), gt(1));
    345         doReturn(FAKE_MEASUREMENT3)
    346                 .when(mMeasurements)
    347                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(2), gt(1));
    348 
    349         // Run the test
    350         mCoverageTest.run(mListener);
    351 
    352         // Verify that all shards were run by checking that we recieved measurements from each
    353         assertThat(mCoverageTest.getMeasurements())
    354                 .containsExactly(FAKE_MEASUREMENT1, FAKE_MEASUREMENT2, FAKE_MEASUREMENT3);
    355     }
    356 
    357     @Test
    358     public void testRun_rerunIndividualTests_failedRun() throws DeviceNotAvailableException {
    359         // Prepare some test data
    360         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    361         doReturn(ImmutableList.of(target)).when(mInstrumentationParser).getInstrumentationTargets();
    362         doReturn(FOO_TESTS)
    363                 .when(mTests)
    364                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    365 
    366         TestRunResult success = mock(TestRunResult.class);
    367         doReturn(false).when(success).isRunFailure();
    368         TestRunResult failure = mock(TestRunResult.class);
    369         doReturn(true).when(failure).isRunFailure();
    370 
    371         // Mocking boilerplate
    372         ITestInvocationListener mockListener = mock(ITestInvocationListener.class);
    373         CodeCoverageTestStub coverageTest = Mockito.spy(new CodeCoverageTestStub());
    374         doReturn(FOO_TESTS).when(mTests).get(PACKAGE_NAME1, RUNNER_NAME1, 0, 1);
    375 
    376         doReturn(failure).when(coverageTest).runTest(eq(target), eq(0), eq(1),
    377                 any(ITestInvocationListener.class));
    378         doReturn(success).when(coverageTest).runTest(eq(target), eq(FOO_TEST1),
    379                 any(ITestInvocationListener.class));
    380         doReturn(failure).when(coverageTest).runTest(eq(target), eq(FOO_TEST2),
    381                 any(ITestInvocationListener.class));
    382         doReturn(success).when(coverageTest).runTest(eq(target), eq(FOO_TEST3),
    383                 any(ITestInvocationListener.class));
    384 
    385         // Run the test
    386         coverageTest.run(mockListener);
    387 
    388         // Verify that individual tests are rerun
    389         verify(coverageTest).runTest(eq(target), eq(0), eq(1), any(ITestInvocationListener.class));
    390         verify(coverageTest).runTest(eq(target), eq(FOO_TEST1), any(ITestInvocationListener.class));
    391         verify(coverageTest).runTest(eq(target), eq(FOO_TEST2), any(ITestInvocationListener.class));
    392         verify(coverageTest).runTest(eq(target), eq(FOO_TEST3), any(ITestInvocationListener.class));
    393     }
    394 
    395     @Test
    396     public void testRun_rerunIndividualTests_missingCoverageFile()
    397             throws DeviceNotAvailableException {
    398         // Prepare some test data
    399         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    400         doReturn(ImmutableList.of(target)).when(mInstrumentationParser).getInstrumentationTargets();
    401         doReturn(FOO_TESTS)
    402                 .when(mTests)
    403                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    404 
    405         TestRunResult success = mock(TestRunResult.class);
    406         doReturn(false).when(success).isRunFailure();
    407 
    408         // Mocking boilerplate
    409         ITestInvocationListener mockListener = mock(ITestInvocationListener.class);
    410         CodeCoverageTestStub coverageTest = Mockito.spy(new CodeCoverageTestStub());
    411         doReturn(FOO_TESTS).when(mTests).get(PACKAGE_NAME1, RUNNER_NAME1, 0, 1);
    412 
    413         doReturn(success)
    414                 .when(coverageTest)
    415                 .runTest(any(InstrumentationTest.class), any(ITestInvocationListener.class));
    416         ITestDevice mockDevice = coverageTest.getDevice();
    417         doReturn(false).doReturn(true).when(mockDevice).doesFileExist(anyString());
    418 
    419         // Run the test
    420         coverageTest.run(mockListener);
    421 
    422         // Verify that individual tests are rerun
    423         verify(coverageTest).runTest(eq(target), eq(0), eq(1), any(ITestInvocationListener.class));
    424         verify(coverageTest).runTest(eq(target), eq(FOO_TEST1), any(ITestInvocationListener.class));
    425         verify(coverageTest).runTest(eq(target), eq(FOO_TEST2), any(ITestInvocationListener.class));
    426         verify(coverageTest).runTest(eq(target), eq(FOO_TEST3), any(ITestInvocationListener.class));
    427     }
    428 
    429     @Test
    430     public void testRun_multipleFormats() throws DeviceNotAvailableException, IOException {
    431         // Prepare some test data
    432         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    433         doReturn(ImmutableList.of(target)).when(mInstrumentationParser).getInstrumentationTargets();
    434         doReturn(FOO_TESTS)
    435                 .when(mTests)
    436                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    437         doReturn(FAKE_MEASUREMENT1)
    438                 .when(mMeasurements)
    439                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    440 
    441         File fakeHtmlReport = new File("/some/fake/xml/report/");
    442         File fakeXmlReport = new File("/some/fake/xml/report.xml");
    443 
    444         // Mocking boilerplate
    445         ITestInvocationListener mockListener = mock(ITestInvocationListener.class);
    446         CodeCoverageTestStub coverageTest = Mockito.spy(new CodeCoverageTestStub());
    447         doReturn(FOO_TESTS).when(mTests).get(PACKAGE_NAME1, RUNNER_NAME1, 0, 1);
    448         doReturn(ImmutableList.of(FakeReportFormat.XML, FakeReportFormat.HTML))
    449                 .when(coverageTest)
    450                 .getReportFormat();
    451         doReturn(fakeHtmlReport)
    452                 .when(coverageTest)
    453                 .generateCoverageReport(anyCollection(), eq(FakeReportFormat.HTML));
    454         doReturn(fakeXmlReport)
    455                 .when(coverageTest)
    456                 .generateCoverageReport(anyCollection(), eq(FakeReportFormat.XML));
    457 
    458         // Run the test
    459         coverageTest.run(mockListener);
    460 
    461         // Verify that the test was run, and that the reports were logged
    462         verify(coverageTest)
    463                 .runTest(any(InstrumentationTest.class), any(ITestInvocationListener.class));
    464         verify(coverageTest).generateCoverageReport(anyCollection(), eq(FakeReportFormat.HTML));
    465         verify(coverageTest).doLogReport(anyString(), eq(FakeReportFormat.HTML.getLogDataType()),
    466                 eq(fakeHtmlReport), any(ITestLogger.class));
    467         verify(coverageTest).generateCoverageReport(anyCollection(), eq(FakeReportFormat.XML));
    468         verify(coverageTest).doLogReport(anyString(), eq(FakeReportFormat.XML.getLogDataType()),
    469                 eq(fakeXmlReport), any(ITestLogger.class));
    470     }
    471 
    472     @Test
    473     public void testGetInstrumentationTargets() throws DeviceNotAvailableException {
    474         // Prepare some test data
    475         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    476         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    477         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    478         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    479 
    480         // Set up mocks
    481         doReturn(ImmutableList.of(target1, target2, target3, target4))
    482                 .when(mInstrumentationParser)
    483                 .getInstrumentationTargets();
    484 
    485         // Get the instrumentation targets
    486         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    487 
    488         // Verify that all of the instrumentation targets were found
    489         assertThat(targets).containsExactly(target1, target2, target3, target4);
    490     }
    491 
    492     @Test
    493     public void testGetInstrumentationTargets_packageFilterSingleFilterSingleResult()
    494             throws DeviceNotAvailableException {
    495         // Prepare some test data
    496         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    497         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    498         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    499         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    500 
    501         // Set up mocks
    502         doReturn(ImmutableList.of(target1, target2, target3, target4))
    503                 .when(mInstrumentationParser)
    504                 .getInstrumentationTargets();
    505         mCoverageTest.setPackageFilter(ImmutableList.of(PACKAGE_NAME1));
    506 
    507         // Get the instrumentation targets
    508         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    509 
    510         // Verify that only the PACKAGE_NAME1 target was returned
    511         assertThat(targets).containsExactly(target1);
    512     }
    513 
    514     @Test
    515     public void testGetInstrumentationTargets_packageFilterSingleFilterMultipleResults()
    516             throws DeviceNotAvailableException {
    517         // Prepare some test data
    518         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    519         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    520         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    521         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    522 
    523         // Set up mocks
    524         doReturn(ImmutableList.of(target1, target2, target3, target4))
    525                 .when(mInstrumentationParser)
    526                 .getInstrumentationTargets();
    527         mCoverageTest.setPackageFilter(ImmutableList.of(PACKAGE_NAME3));
    528 
    529         // Get the instrumentation targets
    530         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    531 
    532         // Verify that both PACKAGE_NAME3 targets were returned
    533         assertThat(targets).containsExactly(target3, target4);
    534     }
    535 
    536     @Test
    537     public void testGetInstrumentationTargets_packageFilterMultipleFilters()
    538             throws DeviceNotAvailableException {
    539         // Prepare some test data
    540         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    541         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    542         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    543         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    544 
    545         // Set up mocks
    546         doReturn(ImmutableList.of(target1, target2, target3, target4))
    547                 .when(mInstrumentationParser)
    548                 .getInstrumentationTargets();
    549         mCoverageTest.setPackageFilter(ImmutableList.of(PACKAGE_NAME1, PACKAGE_NAME2));
    550 
    551         // Get the instrumentation targets
    552         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    553 
    554         // Verify that the PACKAGE_NAME1 and PACKAGE_NAME2 targets were returned
    555         assertThat(targets).containsExactly(target1, target2);
    556     }
    557 
    558     @Test
    559     public void testGetInstrumentationTargets_runnerFilterSingleFilterSingleResult()
    560             throws DeviceNotAvailableException {
    561         // Prepare some test data
    562         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    563         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    564         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    565         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    566 
    567         // Set up mocks
    568         doReturn(ImmutableList.of(target1, target2, target3, target4))
    569                 .when(mInstrumentationParser)
    570                 .getInstrumentationTargets();
    571         mCoverageTest.setRunnerFilter(ImmutableList.of(RUNNER_NAME2));
    572 
    573         // Get the instrumentation targets
    574         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    575 
    576         // Verify that only the RUNNER_NAME2 target was returned
    577         assertThat(targets).containsExactly(target2);
    578     }
    579 
    580     @Test
    581     public void testGetInstrumentationTargets_runnerFilterSingleFilterMultipleResults()
    582             throws DeviceNotAvailableException {
    583         // Prepare some test data
    584         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    585         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    586         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    587         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    588 
    589         // Set up mocks
    590         doReturn(ImmutableList.of(target1, target2, target3, target4))
    591                 .when(mInstrumentationParser)
    592                 .getInstrumentationTargets();
    593         mCoverageTest.setRunnerFilter(ImmutableList.of(RUNNER_NAME1));
    594 
    595         // Get the instrumentation targets
    596         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    597 
    598         // Verify that both RUNNER_NAME1 targets were returned
    599         assertThat(targets).containsExactly(target1, target3);
    600     }
    601 
    602     @Test
    603     public void testGetInstrumentationTargets_runnerFilterMultipleFilters()
    604             throws DeviceNotAvailableException {
    605         // Prepare some test data
    606         InstrumentationTarget target1 = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    607         InstrumentationTarget target2 = new InstrumentationTarget(PACKAGE_NAME2, RUNNER_NAME2, "");
    608         InstrumentationTarget target3 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME1, "");
    609         InstrumentationTarget target4 = new InstrumentationTarget(PACKAGE_NAME3, RUNNER_NAME3, "");
    610 
    611         // Set up mocks
    612         doReturn(ImmutableList.of(target1, target2, target3, target4))
    613                 .when(mInstrumentationParser)
    614                 .getInstrumentationTargets();
    615         mCoverageTest.setRunnerFilter(ImmutableList.of(RUNNER_NAME2, RUNNER_NAME3));
    616 
    617         // Get the instrumentation targets
    618         Collection<InstrumentationTarget> targets = mCoverageTest.getInstrumentationTargets();
    619 
    620         // Verify that the RUNNER_NAME2 and RUNNER_NAME3 targets were returned
    621         assertThat(targets).containsExactly(target2, target4);
    622     }
    623 
    624     @Test
    625     public void testDoesRunnerSupportSharding_true() throws DeviceNotAvailableException {
    626         // Prepare some test data
    627         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    628 
    629         // Set up mocks. Return fewer tests when sharding is enabled.
    630         doReturn(ImmutableList.of(target)).when(mInstrumentationParser).getInstrumentationTargets();
    631         doReturn(FOO_TESTS).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), eq(1));
    632         doReturn(Lists.partition(FOO_TESTS, 2).get(0))
    633                 .when(mTests)
    634                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), gt(1));
    635 
    636         // Verify that the method returns true
    637         assertThat(mCoverageTest.doesRunnerSupportSharding(target)).isTrue();
    638     }
    639 
    640     @Test
    641     public void testDoesRunnerSupportSharding_false() throws DeviceNotAvailableException {
    642         // Prepare some test data
    643         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    644 
    645         // Set up mocks. Return the same number of tests for any number of shards.
    646         doReturn(ImmutableList.of(target)).when(mInstrumentationParser).getInstrumentationTargets();
    647         doReturn(FOO_TESTS)
    648                 .when(mTests)
    649                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    650 
    651         // Verify that the method returns false
    652         assertThat(mCoverageTest.doesRunnerSupportSharding(target)).isFalse();
    653     }
    654 
    655     @Test
    656     public void testGetNumberOfShards() throws DeviceNotAvailableException {
    657         // Prepare some test data
    658         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    659         List<TestIdentifier> tests = new ArrayList<>();
    660         for (int i = 0; i < 10; i++) {
    661             tests.add(new TestIdentifier(PACKAGE_NAME1, String.format("test%d", i)));
    662         }
    663 
    664         // Set up mocks
    665         doReturn(tests).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    666         mCoverageTest.setMaxTestsPerChunk(1);
    667 
    668         // Verify that each test will run in a separate shard
    669         assertThat(mCoverageTest.getNumberOfShards(target)).isEqualTo(tests.size());
    670     }
    671 
    672     @Test
    673     public void testGetNumberOfShards_allTestsInSingleShard() throws DeviceNotAvailableException {
    674         // Prepare some test data
    675         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    676         List<TestIdentifier> tests = new ArrayList<>();
    677         for (int i = 0; i < 10; i++) {
    678             tests.add(new TestIdentifier(PACKAGE_NAME1, String.format("test%d", i)));
    679         }
    680 
    681         // Set up mocks
    682         doReturn(tests).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    683         mCoverageTest.setMaxTestsPerChunk(10);
    684 
    685         // Verify that all tests will run in a single shard
    686         assertThat(mCoverageTest.getNumberOfShards(target)).isEqualTo(1);
    687     }
    688 
    689     @Test
    690     public void testCollectTests() throws DeviceNotAvailableException {
    691         // Prepare some test data
    692         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    693         List<TestIdentifier> tests = new ArrayList<>();
    694         for (int i = 0; i < 10; i++) {
    695             tests.add(new TestIdentifier(PACKAGE_NAME1, String.format("test%d", i)));
    696         }
    697 
    698         // Set up mocks
    699         doReturn(tests).when(mTests).get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), anyInt(), anyInt());
    700 
    701         // Collect the tests
    702         Collection<TestIdentifier> collectedTests = mCoverageTest.collectTests(target, 0, 1);
    703 
    704         // Verify that all of the tests were returned
    705         assertThat(collectedTests).containsExactlyElementsIn(tests);
    706     }
    707 
    708     @Test
    709     public void testCollectTests_withShards() throws DeviceNotAvailableException {
    710         // Prepare some test data
    711         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    712         int numShards = 3;
    713         List<TestIdentifier> tests = new ArrayList<>();
    714         for (int i = 0; i < 10; i++) {
    715             tests.add(new TestIdentifier(PACKAGE_NAME1, String.format("test%d", i)));
    716         }
    717 
    718         // Set up mocks
    719         mCoverageTest.setMaxTestsPerChunk((int) Math.ceil((double) tests.size() / numShards));
    720         doReturn(tests).when(mTests).get(PACKAGE_NAME1, RUNNER_NAME1, 0, 1);
    721         doReturn(tests.subList(0, tests.size() / 2))
    722                 .when(mTests)
    723                 .get(eq(PACKAGE_NAME1), eq(RUNNER_NAME1), eq(0), eq(2));
    724 
    725         List<List<TestIdentifier>> shards =
    726                 Lists.partition(tests, (int) Math.ceil((double) tests.size() / numShards));
    727         int currentIndex = 0;
    728         for (List<TestIdentifier> shard : shards) {
    729             doReturn(shards.get(currentIndex))
    730                     .when(mTests)
    731                     .get(PACKAGE_NAME1, RUNNER_NAME1, currentIndex, shards.size());
    732             currentIndex++;
    733         }
    734 
    735         // Collect the tests in shards
    736         ArrayList<TestIdentifier> allCollectedTests = new ArrayList<>();
    737         for (int shardIndex = 0; shardIndex < numShards; shardIndex++) {
    738             // Verify that each shard contains some tests
    739             Collection<TestIdentifier> collectedTests =
    740                     mCoverageTest.collectTests(target, shardIndex, numShards);
    741             assertThat(collectedTests).containsExactlyElementsIn(shards.get(shardIndex));
    742 
    743             allCollectedTests.addAll(collectedTests);
    744         }
    745         // Verify that all of the tests were returned in the end
    746         assertThat(allCollectedTests).containsExactlyElementsIn(tests);
    747     }
    748 
    749     @Test
    750     public void testCreateTestRunner() throws DeviceNotAvailableException {
    751         // Prepare some test data
    752         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    753 
    754         // Create a test runner
    755         IRemoteAndroidTestRunner runner = mCoverageTest.createTestRunner(target, 0, 1);
    756 
    757         // Verify that the runner has the correct values
    758         assertThat(runner.getPackageName()).isEqualTo(PACKAGE_NAME1);
    759         assertThat(runner.getRunnerName()).isEqualTo(RUNNER_NAME1);
    760     }
    761 
    762     @Test
    763     public void testCreateTestRunner_withArgs() throws DeviceNotAvailableException {
    764         // Prepare some test data
    765         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    766         Map<String, String> args = ImmutableMap.of("arg1", "value1", "arg2", "value2");
    767 
    768         // Set up mocks
    769         mCoverageTest.setInstrumentationArgs(args);
    770 
    771         // Create a test runner
    772         FakeTestRunner runner = (FakeTestRunner) mCoverageTest.createTestRunner(target, 0, 1);
    773 
    774         // Verify that the addInstrumentationArg(..) method was called with each argument
    775         assertThat(runner.getArgs()).containsExactlyEntriesIn(args);
    776     }
    777 
    778     @Test
    779     public void testCreateTestRunner_withShards() throws DeviceNotAvailableException {
    780         // Prepare some test data
    781         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    782         int shardIndex = 3;
    783         int numShards = 5;
    784 
    785         // Create a test runner
    786         FakeTestRunner runner =
    787                 (FakeTestRunner) mCoverageTest.createTestRunner(target, shardIndex, numShards);
    788 
    789         // Verify that the addInstrumentationArg(..) method was called to configure the shards
    790         assertThat(runner.getArgs()).containsEntry("shardIndex", Integer.toString(shardIndex));
    791         assertThat(runner.getArgs()).containsEntry("numShards", Integer.toString(numShards));
    792     }
    793 
    794     @Test
    795     public void testCreateCoverageTest() throws DeviceNotAvailableException {
    796         // Prepare some test data
    797         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    798 
    799         // Create a CodeCoverageTest instance
    800         InstrumentationTest test = mCoverageTest.createTest(target);
    801 
    802         // Verify that the test has the correct values
    803         assertThat(test.getPackageName()).isEqualTo(PACKAGE_NAME1);
    804         assertThat(test.getRunnerName()).isEqualTo(RUNNER_NAME1);
    805         assertThat(test.getInstrumentationArg("coverage")).isEqualTo("true");
    806     }
    807 
    808     @Test
    809     public void testCreateCoverageTest_withArgs() throws DeviceNotAvailableException {
    810         // Prepare some test data
    811         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    812         Map<String, String> args = ImmutableMap.of("arg1", "value1", "arg2", "value2");
    813 
    814         // Set up mocks
    815         mCoverageTest.setInstrumentationArgs(args);
    816 
    817         // Create a CodeCoverageTest instance
    818         InstrumentationTest test = mCoverageTest.createTest(target, 0, 3);
    819 
    820         // Verify that the test has the correct values
    821         for (Map.Entry<String, String> entry : args.entrySet()) {
    822             assertThat(test.getInstrumentationArg(entry.getKey())).isEqualTo(entry.getValue());
    823         }
    824     }
    825 
    826     @Test
    827     public void testCreateCoverageTest_withShards() throws DeviceNotAvailableException {
    828         // Prepare some test data
    829         InstrumentationTarget target = new InstrumentationTarget(PACKAGE_NAME1, RUNNER_NAME1, "");
    830         int shardIndex = 3;
    831         int numShards = 5;
    832 
    833         // Create a CodeCoverageTest instance
    834         InstrumentationTest test = mCoverageTest.createTest(target, shardIndex, numShards);
    835 
    836         // Verify that the addInstrumentationArg(..) method was called to configure the shards
    837         assertThat(test.getInstrumentationArg("shardIndex"))
    838                 .isEqualTo(Integer.toString(shardIndex));
    839         assertThat(test.getInstrumentationArg("numShards")).isEqualTo(Integer.toString(numShards));
    840         assertThat(test.getInstrumentationArg("coverage")).isEqualTo("true");
    841     }
    842 
    843     private static final Answer<Void> CALL_RUNNER =
    844             invocation -> {
    845                 Object[] args = invocation.getArguments();
    846                 ((IRemoteAndroidTestRunner) args[0]).run((ITestRunListener) args[1]);
    847                 return null;
    848             };
    849 
    850     /**
    851      * A fake {@link IRemoteAndroidTestRunner} which simulates a test run by notifying the {@link
    852      * ITestRunListener}s but does not actually run anything.
    853      */
    854     private class FakeTestRunner extends RemoteAndroidTestRunner {
    855         private Map<String, String> mArgs = new HashMap<>();
    856 
    857         FakeTestRunner(String packageName, String runnerName) {
    858             super(packageName, runnerName, null);
    859         }
    860 
    861         @Override
    862         public void addInstrumentationArg(String name, String value) {
    863             super.addInstrumentationArg(name, value);
    864             mArgs.put(name, value);
    865         }
    866 
    867         Map<String, String> getArgs() {
    868             return mArgs;
    869         }
    870 
    871         @Override
    872         public void run(Collection<ITestRunListener> listeners) {
    873             int shardIndex = Integer.parseInt(getArgs().getOrDefault("shardIndex", "0"));
    874             int numShards = Integer.parseInt(getArgs().getOrDefault("numShards", "1"));
    875             List<TestIdentifier> tests =
    876                     mTests.get(getPackageName(), getRunnerName(), shardIndex, numShards);
    877 
    878             // Start the test run
    879             listeners.stream().forEach(l -> l.testRunStarted(getPackageName(), tests.size()));
    880 
    881             // Run each of the tests
    882             for (TestIdentifier test : tests) {
    883                 listeners.stream().forEach(l -> l.testStarted(test));
    884                 listeners.stream().forEach(l -> l.testEnded(test, ImmutableMap.of()));
    885             }
    886 
    887             // Mock out the coverage measurement if necessary
    888             Map<String, String> metrics = new HashMap<>();
    889             if (getArgs().getOrDefault("coverage", "false").equals("true")) {
    890                 String devicePath = String.format(COVERAGE_PATH, getPackageName());
    891                 ByteString measurement =
    892                         mMeasurements.get(getPackageName(), getRunnerName(), shardIndex, numShards);
    893                 mockDeviceFile(devicePath, measurement);
    894                 metrics.put(CodeCoverageTest.COVERAGE_REMOTE_FILE_LABEL, devicePath);
    895             }
    896 
    897             // End the test run
    898             listeners.stream().forEach(l -> l.testRunEnded(TEST_RUN_TIME, metrics));
    899         }
    900     }
    901 
    902     private void mockDeviceFile(String devicePath, ByteString contents) {
    903         Answer<File> pullFile =
    904                 unused -> {
    905                     File ret = mFolder.newFile();
    906                     contents.writeTo(new FileOutputStream(ret));
    907                     return ret;
    908                 };
    909         try {
    910             doReturn(true).when(mDevice).doesFileExist(devicePath);
    911             doAnswer(pullFile).when(mDevice).pullFile(devicePath);
    912         } catch (DeviceNotAvailableException impossible) {
    913             // Mocks won't actually throw.
    914             throw new AssertionError(impossible);
    915         }
    916     }
    917 }
    918