1/**
2 * This script plugin is used to bundle the host test (e.g. Robolectric) results and dist it in
3 * a location where TradeFed knows how to parse.
4 *
5 * - If a non-dist build is run with test, it will run the normal unit tests, failing the build if
6 *   there are test failures.
7 * - If a dist build is run with test (e.g. ./gradlew dist test), the build will ignore any test
8 *   failures, and will create a zip of the XML test reports for each test run, and copy them to
9 *   dist/host-test-reports for consumption by TradeFed.
10 */
11
12apply plugin: 'dist'
13apply plugin: 'jacoco'
14
15// If unit tests are run as part of the build, dist the test XML reports to host-test-reports/*.zip
16android.unitTestVariants.all { variant ->
17    def task = tasks.findByName('test' + variant.name.capitalize())
18    gradle.taskGraph.whenReady { taskGraph ->
19        // Ignore the failures, so the build continues even on test errors when the build is
20        // running with 'dist'. (Usually as part of a build server build)
21        task.ignoreFailures = taskGraph.hasTask(tasks.dist)
22    }
23
24    def junitReport = task.reports.junitXml
25    if (junitReport.enabled) {
26        // Create a zip file of the XML test reports
27        def zipTask = tasks.create("zipResultsOf${task.name.capitalize()}", Zip) {
28            from junitReport.destination
29            archiveName = task.name + 'Result.zip'
30            destinationDir = junitReport.destination.parentFile
31        }
32        task.finalizedBy zipTask
33
34        // Copy the test reports to dist/host-test-reports
35        // The file path and format should match GradleHostBasedTest class in TradeFed.
36        tasks.dist.mustRunAfter zipTask
37        dist.file zipTask.archivePath.path, "host-test-reports/${zipTask.archiveName}"
38    }
39}
40
41/*
42 * The section below adds code coverage to all the unitTest targets. By default, the jacoco plugin
43 * only adds to the 'java' plugin and not the Android ones.
44 *
45 * For each unitTest task "fooUnitTest", a new target "fooUnitTestCoverage" will be generated for
46 * to generate the jacoco report.
47 */
48android.testOptions.unitTests.all {
49    // Fix robolectric tests reporting 0 coverage on newer versions of the plugin.
50    jacoco {
51        includeNoLocationClasses = true
52    }
53}
54
55// Define the main coverage task if it does not exist. This task generates coverage report for all
56// unit tests.
57def coverageTask = tasks.findByName('coverage') ?: tasks.create('coverage') {
58    group = "Reporting"
59    description = "Generate Jacoco coverage reports"
60}
61
62android.unitTestVariants.all { variant ->
63    def testTaskName = "test${variant.name.capitalize()}"
64    def testTask = tasks.findByName(testTaskName)
65
66    // Create coverage task of form 'testFlavorCoverageUnitTestCoverage' depending on
67    // 'testFlavorCoverageUnitTest'
68    def jacocoTask = tasks.create("${testTaskName}Coverage", JacocoReport) {
69        group = "Reporting"
70        description = "Generate a Jacoco coverage report for robolectric tests on ${variant.name}."
71
72        classDirectories = fileTree(
73            dir: "${project.buildDir}/intermediates/classes/" +
74                "${variant.productFlavors[0].name}/${variant.buildType.name}",
75            excludes: ['**/R.class',
76                       '**/R$*.class',
77                       '**/BuildConfig.*',
78                       '**/Manifest*.*']
79        )
80
81        sourceDirectories = files(variant.testedVariant.sourceSets.collect { it.java.srcDirs })
82        executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
83
84        reports {
85            xml.enabled = true
86            html.enabled = true
87        }
88    }
89    jacocoTask.dependsOn testTask
90
91    // Create a zip file of the HTML coverage reports
92    def zipTask = tasks.create("zipResultsOf${jacocoTask.name.capitalize()}", Zip) {
93        from jacocoTask.reports.html.destination
94        archiveName = "${testTaskName}HtmlCoverage.zip"
95        destinationDir = jacocoTask.reports.html.destination.parentFile
96    }
97    jacocoTask.finalizedBy zipTask
98
99    // Copy the coverage reports to dist/host-test-coverage
100    // The file path and format should match JacocoLogForwarder class in TradeFed.
101    tasks.dist.mustRunAfter jacocoTask
102    dist.file jacocoTask.reports.xml.destination.path, "host-test-coverage/${jacocoTask.name}.xml"
103
104    tasks.dist.mustRunAfter zipTask
105    dist.file zipTask.archivePath.path, "host-test-coverage/${zipTask.archiveName}"
106
107    coverageTask.dependsOn(jacocoTask)
108}
109