Skip to content

Commit 120004e

Browse files
Fix code coverage (#1369)
1 parent a87190c commit 120004e

File tree

6 files changed

+114
-12
lines changed

6 files changed

+114
-12
lines changed

.github/workflows/test-and-build-workflow.yml

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515

1616
test-and-build-linux:
1717
needs: Get-CI-Image-Tag
18+
timeout-minutes: 25
1819
env:
1920
TEST_FILTER: ${{ matrix.test_filter }}
2021
strategy:
@@ -51,24 +52,40 @@ jobs:
5152
# This is a hack, but this step creates a link to the X: mounted drive, which makes the path
5253
# short enough to work on Windows
5354
- name: Build with Gradle
55+
timeout-minutes: 20
5456
run: |
5557
chown -R 1000:1000 `pwd`
5658
su `id -un 1000` -c "./gradlew build ${{ env.TEST_FILTER }}"
59+
- name: Generate Jacoco Test Report
60+
if: always() && matrix.java == 21
61+
run: |
62+
su `id -un 1000` -c "./gradlew jacocoTestReport"
63+
- name: Upload coverage XML
64+
uses: actions/upload-artifact@v4
65+
if: always() && matrix.java == 21
66+
with:
67+
name: coverage-xml-${{ matrix.java }}-${{ matrix.feature }}
68+
path: build/reports/jacoco/**/jacocoTestReport.xml
69+
if-no-files-found: warn
70+
overwrite: 'true'
5771
- name: Upload failed logs
5872
uses: actions/upload-artifact@v4
5973
if: ${{ failure() }}
6074
with:
6175
name: logs-${{ matrix.java }}-${{ matrix.feature }}
6276
path: build/testclusters/integTest-*/logs/*
6377
overwrite: 'true'
78+
- name: Upload test reports
79+
uses: actions/upload-artifact@v4
80+
if: ${{ failure() }}
81+
with:
82+
name: test-reports-linux-${{ matrix.java }}-${{ matrix.feature }}
83+
path: build/reports/
84+
overwrite: 'true'
6485
- name: Create Artifact Path
6586
run: |
6687
mkdir -p index-management-artifacts
6788
cp ./build/distributions/*.zip index-management-artifacts
68-
- name: Uploads coverage
69-
uses: codecov/codecov-action@v5
70-
with:
71-
token: ${{ secrets.CODECOV_TOKEN }}
7289
# This step uses the upload-artifact Github action: https://github.com/actions/upload-artifact
7390
- name: Upload Artifacts
7491
# v4 requires node.js 20 which is not supported
@@ -134,3 +151,41 @@ jobs:
134151
name: index-management-plugin-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.feature }}
135152
path: index-management-artifacts
136153
overwrite: 'true'
154+
155+
report-coverage:
156+
needs: ["test-and-build-linux"]
157+
if: always()
158+
runs-on: ubuntu-latest
159+
steps:
160+
- uses: actions/checkout@v4
161+
- uses: actions/download-artifact@v4
162+
with:
163+
path: downloaded-artifacts
164+
pattern: coverage-xml-*
165+
166+
- name: Display structure of downloaded files
167+
run: ls -R
168+
working-directory: downloaded-artifacts
169+
170+
- name: Check if coverage files exist
171+
id: check_coverage
172+
run: |
173+
if find downloaded-artifacts -name "*.xml" -type f | grep -q .; then
174+
echo "Coverage XML files found"
175+
echo "has_coverage=true" >> $GITHUB_OUTPUT
176+
else
177+
echo "No coverage XML files found"
178+
echo "has_coverage=false" >> $GITHUB_OUTPUT
179+
fi
180+
181+
- name: Upload Coverage with retry
182+
if: steps.check_coverage.outputs.has_coverage == 'true'
183+
uses: Wandalen/[email protected]
184+
with:
185+
attempt_limit: 5
186+
attempt_delay: 2000
187+
action: codecov/codecov-action@v4
188+
with: |
189+
token: ${{ secrets.CODECOV_TOKEN }}
190+
fail_ci_if_error: true
191+
verbose: true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ bin/
1717
spi/bin/
1818
src/test/resources/notifications*
1919

20+
.claude
21+
CLAUDE.md

DEVELOPER_GUIDE.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- [Setup](#setup)
66
- [Build](#build)
77
- [Building from the command line](#building-from-the-command-line)
8+
- [Code Coverage](#code-coverage)
89
- [Debugging](#debugging)
910
- [Using IntelliJ IDEA](#using-intellij-idea)
1011
- [Submitting Changes](#submitting-changes)
@@ -63,6 +64,31 @@ However, to build the `index management` plugin project, we also use the OpenSea
6364

6465
When launching a cluster using one of the above commands, logs are placed in `build/testclusters/integTest-0/logs`. Though the logs are teed to the console, in practices it's best to check the actual log file.
6566

67+
### Code Coverage
68+
69+
The project supports generating code coverage reports using JaCoCo.
70+
71+
#### Generating Coverage Reports
72+
73+
To generate code coverage reports
74+
75+
```bash
76+
./gradlew check -Dtests.coverage=true
77+
```
78+
79+
Or run any tests, and generate test report
80+
81+
```bash
82+
./gradlew test
83+
./gradlew jacocoTestReport
84+
```
85+
86+
#### Coverage Report Locations
87+
88+
After running with coverage enabled, reports are generated in:
89+
- **HTML Report**: `build/reports/jacoco/test/html/index.html` (human readable)
90+
- **XML Report**: `build/reports/jacoco/test/jacocoTestReport.xml` (for tools like Codecov)
91+
6692
### Debugging
6793

6894
Sometimes it is useful to attach a debugger to either the OpenSearch cluster or the integ tests to see what's going on. When running unit tests, hit **Debug** from the IDE's gutter to debug the tests. For the OpenSearch cluster or the integ tests, first, make sure start a debugger listening on port `5005`.

build-tools/coverage.gradle

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
// Get gradle to generate the required jvm agent arg for us using a dummy tasks of type Test. Unfortunately Elastic's
2121
// testing tasks don't derive from Test so the jacoco plugin can't do this automatically.
22-
def jacocoDir = "${buildDir}/jacoco"
22+
def jacocoDir = layout.buildDirectory.dir("jacoco").get().asFile.absolutePath
2323

2424
tasks.register("dummyTest", Test) {
2525
enabled = false
@@ -42,12 +42,28 @@ tasks.register("dummyIntegTest", Test) {
4242
}
4343

4444
integTest {
45-
systemProperty 'jacoco.dir', "${jacocoDir}"
45+
systemProperty 'jacoco.dir', jacocoDir
4646
}
4747

4848
jacocoTestReport {
49-
dependsOn integTest, test
50-
executionData dummyTest.jacoco.destinationFile, dummyIntegTest.jacoco.destinationFile
49+
// Use mustRunAfter instead of dependsOn to avoid re-running tests
50+
// This ensures proper ordering without forcing test execution
51+
mustRunAfter test, integTest
52+
53+
// Configure execution data to use any available .exec files
54+
executionData.from fileTree(dir: jacocoDir, include: '*.exec')
55+
56+
// Make the task skip only if no execution data exists at all
57+
// Using a closure to defer the check until execution time
58+
onlyIf {
59+
def execFiles = fileTree(dir: jacocoDir, include: '*.exec').files
60+
def hasExecFiles = execFiles.any { it.exists() }
61+
if (!hasExecFiles) {
62+
println("Skipping jacocoTestReport: No execution data files found in ${jacocoDir}")
63+
}
64+
hasExecFiles
65+
}
66+
5167
sourceDirectories.from = "src/main/kotlin"
5268
classDirectories.from = sourceSets.main.output
5369
reports {
@@ -58,8 +74,6 @@ jacocoTestReport {
5874

5975
allprojects{
6076
afterEvaluate {
61-
jacocoTestReport.dependsOn integTest
62-
6377
testClusters.integTest {
6478
jvmArgs " ${dummyIntegTest.jacoco.getAsJvmArg()}".replace('javaagent:','javaagent:/')
6579
systemProperty 'com.sun.management.jmxremote', "true"
@@ -69,4 +83,11 @@ allprojects{
6983
systemProperty 'java.rmi.server.hostname', "127.0.0.1"
7084
}
7185
}
86+
}
87+
88+
// Attach code coverage report task to Gradle check task when coverage is enabled
89+
if (System.getProperty("tests.coverage")) {
90+
project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME).configure {
91+
dependsOn tasks.named('jacocoTestReport', JacocoReport)
92+
}
7293
}

build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ def usingMultiNode = project.properties.containsKey('numNodes')
134134
if (!usingRemoteCluster && !usingMultiNode) {
135135
apply from: 'build-tools/coverage.gradle'
136136
}
137-
check.dependsOn jacocoTestReport
138137

139138
opensearchplugin {
140139
name 'opensearch-index-management'

spi/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ jacocoTestReport {
4444
html.destination file("${buildDir}/jacoco/")
4545
}
4646
}
47-
check.dependsOn jacocoTestReport
4847

4948
repositories {
5049
mavenLocal()

0 commit comments

Comments
 (0)