From ca3ced981f97e2ceb0ba5e9a34fa279fdaddefed Mon Sep 17 00:00:00 2001 From: Tianli Feng Date: Tue, 10 Aug 2021 07:23:46 -0700 Subject: [PATCH] Add support to generate code coverage report with JaCoCo (#971) * add jacoco plugin Signed-off-by: Tianli Feng * config aggregated jacoco report Signed-off-by: Tianli Feng * Skip generating report if no test in subproject Signed-off-by: Tianli Feng * Add jacoco plugin into root project Signed-off-by: Tianli Feng * test aggregate code coverage report Signed-off-by: Tianli Feng * Can generate aggregated unit test coverage report Signed-off-by: Tianli Feng * Can generate aggregated test report with source file linked Signed-off-by: Tianli Feng * Some cleanup, but jacocoReport is not dependson Test Signed-off-by: Tianli Feng * cleanup Signed-off-by: Tianli Feng * get unit test code coverage report Signed-off-by: Tianli Feng * change 'enabled == true' to 'enabled' Signed-off-by: Tianli Feng * add a comment for selectedsubprojects Signed-off-by: Tianli Feng * add tasks to generate code coverage report for unit test and integration test Signed-off-by: Tianli Feng * fix typo in variable Signed-off-by: Tianli Feng * Correct the task to get codecoverage for unit test and integtest Signed-off-by: Tianli Feng * Make code coverage report task run after test Signed-off-by: Tianli Feng * apply gradle configuration aciidance api Signed-off-by: Tianli Feng * apply jacoco plugin in BuildPlugin in all case Signed-off-by: Tianli Feng * Put file path list of integration test exec data in a variable Signed-off-by: Tianli Feng * Apply gradle configuration aviodance api to register task instead of create task Signed-off-by: Tianli Feng * merge 2 jacocoreport configurations Signed-off-by: Tianli Feng * Add some comments in gradle script Signed-off-by: Tianli Feng * Attach code coverage report task to gralde check task Signed-off-by: Tianli Feng * add a space Signed-off-by: Tianli Feng * get code coverage report after check task on demand and get report in html format on demand Signed-off-by: Tianli Feng --- build.gradle | 1 + .../org/opensearch/gradle/BuildPlugin.groovy | 1 + gradle/code-coverage.gradle | 94 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 gradle/code-coverage.gradle diff --git a/build.gradle b/build.gradle index 0fe902015e9..7a9dc40e38a 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,7 @@ apply from: 'gradle/local-distribution.gradle' apply from: 'gradle/fips.gradle' apply from: 'gradle/run.gradle' apply from: 'gradle/missing-javadoc.gradle' +apply from: 'gradle/code-coverage.gradle' // common maven publishing configuration allprojects { diff --git a/buildSrc/src/main/groovy/org/opensearch/gradle/BuildPlugin.groovy b/buildSrc/src/main/groovy/org/opensearch/gradle/BuildPlugin.groovy index c76a78bbfad..0a1bc7dfd23 100644 --- a/buildSrc/src/main/groovy/org/opensearch/gradle/BuildPlugin.groovy +++ b/buildSrc/src/main/groovy/org/opensearch/gradle/BuildPlugin.groovy @@ -81,6 +81,7 @@ class BuildPlugin implements Plugin { configureLicenseAndNotice(project) project.pluginManager.apply('opensearch.publish') project.pluginManager.apply(DependenciesInfoPlugin) + project.pluginManager.apply('jacoco') PrecommitTasks.create(project, true) } diff --git a/gradle/code-coverage.gradle b/gradle/code-coverage.gradle new file mode 100644 index 00000000000..1c2ee64fe18 --- /dev/null +++ b/gradle/code-coverage.gradle @@ -0,0 +1,94 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +apply plugin: 'jacoco' + +repositories { + mavenCentral() +} + +allprojects { + plugins.withId('jacoco') { + // The default JaCoCo version in Gradle 6.6.1 is 0.8.5, but at least version 0.8.6 officially supports Java 14 + jacoco.toolVersion = '0.8.7' + } +} + +def codeCoverageReportTask = tasks.register("codeCoverageReport", JacocoReport) { + description = 'Generates aggregate report from all subprojects.' + executionData.setFrom fileTree(dir: '.', include: '**/build/jacoco/*.exec') +} + +tasks.register("codeCoverageReportForUnitTest", JacocoReport) { + description = 'Generates aggregate report from all subprojects for unit test.' + executionData.setFrom fileTree(dir: '.', include: '**/build/jacoco/test.exec') +} + +tasks.register("codeCoverageReportForIntegrationTest", JacocoReport) { + description = 'Generates aggregate report from all subprojects for integration test.' + // These kinds of tests are integration test, and the tests can be ran by Gradle tasks with the same name + def integrationTestExecPathList = ['**/build/jacoco/integTest.exec', + '**/build/jacoco/internalClusterTest.exec', + '**/build/jacoco/javaRestTest.exec', + '**/build/jacoco/yamlRestTest.exec' ] + executionData.setFrom fileTree(dir: '.', include: integrationTestExecPathList) +} + +tasks.withType(JacocoReport).configureEach { + group = JavaBasePlugin.VERIFICATION_GROUP + + // Select projects with corresponding tests in order to run proper tests and select proper classes to generate the report + def projectsWithJavaPlugin = subprojects.findAll { it.pluginManager.hasPlugin('java') } + def projectsWithUnitTest = projectsWithJavaPlugin.findAll { it.tasks.findByName('test').enabled } + def projectsWithIntegTest = projectsWithJavaPlugin.findAll {it.tasks.findByName('integTest')} + def projectsWithInternalClusterTest = projectsWithJavaPlugin.findAll {it.tasks.findByName('internalClusterTest')} + def projectsWithJavaRestTest = projectsWithJavaPlugin.findAll {it.tasks.findByName('javaRestTest')} + def projectsWithYamlRestTest = projectsWithJavaPlugin.findAll {it.tasks.findByName('yamlRestTest')} + def projectsWithIntegrationTest = projectsWithIntegTest + projectsWithInternalClusterTest + projectsWithJavaRestTest + projectsWithYamlRestTest + def projectsWithTest = projectsWithUnitTest + projectsWithIntegrationTest + + def selectedProjects + switch (name) { + case "codeCoverageReportForUnitTest": + dependsOn projectsWithUnitTest.test + selectedProjects = projectsWithUnitTest + break + case "codeCoverageReportForIntegrationTest": + dependsOn projectsWithIntegTest.integTest + dependsOn projectsWithInternalClusterTest.internalClusterTest + dependsOn projectsWithJavaRestTest.javaRestTest + dependsOn projectsWithYamlRestTest.yamlRestTest + selectedProjects = projectsWithIntegrationTest + break + default: + dependsOn projectsWithUnitTest.test + dependsOn projectsWithIntegTest.integTest + dependsOn projectsWithInternalClusterTest.internalClusterTest + dependsOn projectsWithJavaRestTest.javaRestTest + dependsOn projectsWithYamlRestTest.yamlRestTest + selectedProjects = projectsWithTest + break + } + sourceDirectories.setFrom files(selectedProjects.sourceSets.main.allSource.srcDirs) + classDirectories.setFrom files(selectedProjects.sourceSets.main.output) + + reports { + xml.enabled true + // Code coverage report in HTML format is on demand, since it takes up 100+MB of disk space. + if (System.getProperty('tests.coverage.html_report')) { + html.enabled true + } + } +} + +if (System.getProperty("tests.coverage")) { + // Attach code coverage report task to Gradle check task + project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME).configure { + dependsOn codeCoverageReportTask + } +}