From 99741d687cb26a8f0632af76032797aae383fab8 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Mon, 12 Oct 2026 22:22:43 +0800 Subject: [PATCH 1/3] ci(framework): bound linux workers and retain test diagnostics --- .../upload-test-diagnostics/action.yml | 36 +++++++++++++++++++ .github/workflows/pr-build.yml | 24 +++++++++++-- framework/build.gradle | 4 +++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 .github/actions/upload-test-diagnostics/action.yml diff --git a/.github/actions/upload-test-diagnostics/action.yml b/.github/actions/upload-test-diagnostics/action.yml new file mode 100644 index 00000000000..377c61a302a --- /dev/null +++ b/.github/actions/upload-test-diagnostics/action.yml @@ -0,0 +1,36 @@ +name: Upload test diagnostics +description: Preserve test reports, application logs, and JVM crash reports after a failed build. + +runs: + using: composite + steps: + - name: Report available memory and process limits + if: always() + shell: bash + run: | + ulimit -a + if command -v free >/dev/null 2>&1; then + free -m + elif command -v vm_stat >/dev/null 2>&1; then + vm_stat + fi + for counter in /sys/fs/cgroup/memory.events /sys/fs/cgroup/memory.current /sys/fs/cgroup/memory.max; do + if [ -r "$counter" ]; then + echo "$counter" + cat "$counter" + fi + done + + - name: Upload diagnostic files + if: always() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: test-diagnostics-${{ github.job }}-${{ github.run_attempt }} + path: | + **/build/test-results/** + **/build/reports/tests/** + **/logs/tron-test*.log* + **/hs_err_pid*.log + if-no-files-found: warn + retention-days: 7 + compression-level: 1 diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index c7a5a6f4160..fe9f5261758 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -63,6 +63,10 @@ jobs: java -jar "$JAR" db archive -h java -jar "$JAR" keystore --help + - name: Upload test diagnostics + if: failure() + uses: ./.github/actions/upload-test-diagnostics + build-ubuntu: name: Build ubuntu24 (JDK 17 / aarch64) if: ${{ github.event_name == 'pull_request' || inputs.job == 'all' || inputs.job == 'ubuntu' }} @@ -91,7 +95,8 @@ jobs: restore-keys: ubuntu24-aarch64-gradle- - name: Build - run: ./gradlew clean build --no-daemon + # Bound worker concurrency while retaining parallelism within the 60-minute job limit. + run: ./gradlew clean build --no-daemon --max-workers=2 --info --stacktrace - name: Toolkit jar smoke test run: | @@ -102,6 +107,10 @@ jobs: java -jar "$JAR" db archive -h java -jar "$JAR" keystore --help + - name: Upload test diagnostics + if: failure() + uses: ./.github/actions/upload-test-diagnostics + docker-build-rockylinux: name: Build rockylinux (JDK 8 / x86_64) if: ${{ github.event_name == 'pull_request' || inputs.job == 'all' || inputs.job == 'rockylinux' }} @@ -143,7 +152,8 @@ jobs: run: ./gradlew --stop || true - name: Build - run: ./gradlew clean build --no-daemon + # Bound worker concurrency while retaining parallelism within the 60-minute job limit. + run: ./gradlew clean build --no-daemon --max-workers=2 --info --stacktrace - name: Toolkit jar smoke test run: | @@ -155,7 +165,11 @@ jobs: java -jar "$JAR" keystore --help - name: Test with RocksDB engine - run: ./gradlew :framework:testWithRocksDb --no-daemon + run: ./gradlew :framework:testWithRocksDb --no-daemon --max-workers=2 --info --stacktrace + + - name: Upload test diagnostics + if: failure() + uses: ./.github/actions/upload-test-diagnostics docker-build-debian11: name: Build debian11 (JDK 8 / x86_64) @@ -222,6 +236,10 @@ jobs: **/build/reports/jacoco/test/jacocoTestReport.xml if-no-files-found: error + - name: Upload test diagnostics + if: failure() + uses: ./.github/actions/upload-test-diagnostics + coverage-base: name: Coverage Base (JDK 8 / x86_64) if: ${{ github.event_name == 'pull_request' }} diff --git a/framework/build.gradle b/framework/build.gradle index 8edd6714f95..2dfc9470e6a 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -136,6 +136,10 @@ def configureTestTask = { Task t -> } t.maxHeapSize = "512m" t.maxParallelForks = Math.max(1, Math.min(4, Runtime.runtime.availableProcessors())) + if ('true'.equalsIgnoreCase(System.getenv('CI'))) { + // Keep fatal test-JVM diagnostics in the task output directory for CI artifacts. + t.jvmArgs "-XX:ErrorFile=${t.temporaryDir}/hs_err_pid%p.log" + } t.systemProperty 'runPrecompileBenchmark', System.getProperty('runPrecompileBenchmark', 'false') t.doFirst { From 0d663d73e08331d9a05802882e91c9c5cd34fe5d Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Tue, 13 Oct 2026 01:14:31 +0800 Subject: [PATCH 2/3] ci(framework): rerun linux tasks for stability validation --- .github/workflows/pr-build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index fe9f5261758..f4c8a86eca0 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -96,7 +96,8 @@ jobs: - name: Build # Bound worker concurrency while retaining parallelism within the 60-minute job limit. - run: ./gradlew clean build --no-daemon --max-workers=2 --info --stacktrace + # Execute tests on every retry instead of restoring their outputs from the build cache. + run: ./gradlew clean build --no-daemon --max-workers=2 --rerun-tasks --info --stacktrace - name: Toolkit jar smoke test run: | @@ -153,7 +154,8 @@ jobs: - name: Build # Bound worker concurrency while retaining parallelism within the 60-minute job limit. - run: ./gradlew clean build --no-daemon --max-workers=2 --info --stacktrace + # Execute tests on every retry instead of restoring their outputs from the build cache. + run: ./gradlew clean build --no-daemon --max-workers=2 --rerun-tasks --info --stacktrace - name: Toolkit jar smoke test run: | @@ -165,7 +167,7 @@ jobs: java -jar "$JAR" keystore --help - name: Test with RocksDB engine - run: ./gradlew :framework:testWithRocksDb --no-daemon --max-workers=2 --info --stacktrace + run: ./gradlew :framework:testWithRocksDb --no-daemon --max-workers=2 --rerun-tasks --info --stacktrace - name: Upload test diagnostics if: failure() From ccba12aa7228aa658aa31d20baf18b6b6cfa82be Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Tue, 13 Oct 2026 10:09:54 +0800 Subject: [PATCH 3/3] test(framework): await reward calculation before mutating store --- .../org/tron/core/services/ComputeRewardTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java b/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java index a1bffd5bf1f..0e5dbec1776 100644 --- a/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java +++ b/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java @@ -10,7 +10,9 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -248,8 +250,15 @@ private void setUp() { } @Test - public void query() { + public void query() throws InterruptedException { Assert.assertEquals(3189, mortgageService.queryReward(OWNER_ADDRESS)); + // queryReward() can return before the background Merkle-root calculation finishes. + // Wait for it before modifying or closing the store used by that calculation. + ExecutorService rewardExecutor = ReflectUtils.getFieldValue(rewardViCalService, "es"); + rewardExecutor.shutdown(); + Assert.assertTrue("Reward calculation did not terminate before modifying its store", + rewardExecutor.awaitTermination(10, TimeUnit.SECONDS)); + // mock root is error rewardViStore.put("test".getBytes(), "test".getBytes()); ReflectUtils.invokeMethod(rewardViCalService,"maybeRun");