This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch UNOMI-979-scheduler-lock-lease
in repository https://gitbox.apache.org/repos/asf/unomi.git
The following commit(s) were added to refs/heads/UNOMI-979-scheduler-lock-lease
by this push:
new 753f084e0 UNOMI-979: Report flaky unit tests and archive reports on CI
753f084e0 is described below
commit 753f084e0aaad3930dd1967b976d53647bdab719
Author: Serge Huber <[email protected]>
AuthorDate: Mon Aug 17 14:21:47 2026 +0200
UNOMI-979: Report flaky unit tests and archive reports on CI
Intermittent unit-test failures were invisible in two directions. A test
that
failed once and would have passed on a retry turned the whole build red,
and a
test that already passed on someone's manual re-run left no record at all -
so
nobody could tell which suites were unreliable, or whether a deflaking
change
had worked. Both of the scheduler failures investigated under this ticket
had to
be diagnosed from a bare assertion message.
The unit-test job now:
* Retries a failing test twice (-Dsurefire.rerunFailingTestsCount=2, passed
via
the existing MAVEN_EXTRA_OPTS hook). This runner has 2 vCPU and several
suites
are timing-sensitive, so one unlucky scheduling hiccup should not fail a
build.
* Surfaces every flake in the job summary as a table of test, retry count
and
first failure message. This is the half that keeps the retry honest: a
test
passing only on retry is a real intermittent failure, and without the
summary
the retry would simply convert a red build into an invisible green one.
* Archives surefire reports when the build failed or anything flaked - the
runs
where the reports, including the scheduler state and DEBUG traces the new
SchedulerDiagnosticsExtension writes into them, are worth keeping.
Skipped on
clean runs so artifacts do not accumulate on every push.
* Publishes a JUnit check for unit tests, mirroring what the
integration-test
job already does, so per-test results are visible without opening the log.
Job timeout raised 15 -> 20 minutes: retried failures add time on a red
build,
and a timeout is a worse signal than a clean failure.
Verified by running a test rigged to fail on its first attempt only:
Surefire
reports "Flakes: 1", the build goes green, flakyFailure lands in the XML,
and the
detection script picks it up and writes the summary table. The script was
also
checked against synthetic reports to confirm it flags only the flaky case.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.github/workflows/unomi-ci-build-tests.yml | 71 +++++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/unomi-ci-build-tests.yml
b/.github/workflows/unomi-ci-build-tests.yml
index 076ab448e..ebb283fef 100644
--- a/.github/workflows/unomi-ci-build-tests.yml
+++ b/.github/workflows/unomi-ci-build-tests.yml
@@ -21,7 +21,9 @@ jobs:
unit-tests:
name: Execute unit tests
runs-on: ubuntu-latest
- timeout-minutes: 15
+ # Slightly above the previous 15: retried failures (rerunFailingTestsCount
below) add time
+ # on a red build, and a timeout is a much worse signal than a clean
failure.
+ timeout-minutes: 20
steps:
- uses: actions/checkout@v5
- name: Set up JDK 17
@@ -36,12 +38,79 @@ jobs:
sudo apt-get install -y graphviz
dot -V
- name: Build and Unit tests
+ env:
+ # Retry a failing test twice before calling the build red. Several
suites (notably the
+ # scheduler ones) are timing-sensitive and this runner has 2 vCPU, so
a single unlucky
+ # scheduling hiccup should not fail a whole build. A test that only
passes on retry is
+ # NOT silently forgiven: Surefire records it as a flake, and the step
below surfaces
+ # every one in the job summary so the flake rate stays visible instead
of becoming
+ # invisible green.
+ MAVEN_EXTRA_OPTS: -Dsurefire.rerunFailingTestsCount=2
run: ./build.sh --ci
# Keep only third-party dependencies in the post-job Maven cache: Unomi's
own
# snapshots are rebuilt every run and would only bloat the cache / risk
staleness
- name: Clean Unomi artifacts from Maven cache
if: always()
run: rm -rf ~/.m2/repository/org/apache/unomi
+ # A flake is a test that failed and then passed on retry. The build is
green, so without
+ # this the signal is lost entirely — which is how the scheduler suites
stayed unreliable
+ # for as long as they did.
+ - name: Detect flaky tests
+ id: flakes
+ if: always()
+ run: |
+ python3 - <<'PY' >> "$GITHUB_STEP_SUMMARY"
+ import glob, os, xml.etree.ElementTree as ET
+ flaky = []
+ for path in glob.glob('**/target/surefire-reports/TEST-*.xml',
recursive=True):
+ try:
+ root = ET.parse(path).getroot()
+ except ET.ParseError:
+ continue
+ for case in root.iter('testcase'):
+ reruns = case.findall('flakyFailure') +
case.findall('flakyError')
+ if reruns:
+ msg = (reruns[0].get('message') or
'').strip().replace('\n', ' ')
+ flaky.append((case.get('classname', '?'), case.get('name',
'?'),
+ len(reruns), msg[:160]))
+ if flaky:
+ print('### :warning: Flaky tests detected\n')
+ print('These failed and then passed on retry. The build is green,
but each one is')
+ print('a real intermittent failure worth investigating.\n')
+ print('| Test | Retries | First failure |')
+ print('| --- | --- | --- |')
+ for cls, name, n, msg in sorted(flaky):
+ print(f'| `{cls}.{name}` | {n} | {msg or "—"} |')
+ else:
+ print('### No flaky tests detected\n')
+ with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
+ out.write(f'found={"true" if flaky else "false"}\n')
+ out.write(f'count={len(flaky)}\n')
+ PY
+ # Uploaded when the build failed OR when something only passed on retry:
those are exactly
+ # the runs where the reports (and the scheduler diagnostics dumped into
them) are worth
+ # keeping. Skipped on a clean green run so this does not accumulate on
every push.
+ - name: Archive unit test reports
+ uses: actions/upload-artifact@v6
+ if: always() && (job.status == 'failure' || steps.flakes.outputs.found
== 'true')
+ with:
+ name: unit-test-reports-jdk17-${{ github.run_number }}
+ path: |
+ **/target/surefire-reports/**
+ if-no-files-found: ignore
+ retention-days: 14
+ # Always publish so a later "re-run failed jobs" pass updates the check to
green, matching
+ # the integration-test job's behaviour.
+ - name: Publish Test Report
+ uses: mikepenz/action-junit-report@v3
+ if: always()
+ continue-on-error: true
+ with:
+ report_paths: '**/target/surefire-reports/TEST-*.xml'
+ check_name: 'JUnit Test Report (unit tests)'
+ update_check: true
+ fail_on_failure: false
+ require_tests: false
integration-tests:
name: Execute integration tests