Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 124 additions & 14 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ jobs:
restore-keys: macos26-${{ matrix.arch }}-gradle-

- name: Build
run: ./gradlew clean build --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew clean build --no-daemon --console=plain 2>&1 | tee ci-logs/build.log

- name: Toolkit jar smoke test
run: |
Expand All @@ -63,6 +67,17 @@ jobs:
java -jar "$JAR" db archive -h
java -jar "$JAR" keystore --help

- name: Upload test diagnostics
if: failure()
uses: actions/upload-artifact@v6
with:
name: tron-test-logs-${{ github.job }}-jdk${{ matrix.java }}-${{ matrix.arch }}
path: |
**/logs/tron-test.log
ci-logs/*.log
if-no-files-found: warn
retention-days: 7

build-ubuntu:
name: Build ubuntu24 (JDK 17 / aarch64)
if: ${{ github.event_name == 'pull_request' || inputs.job == 'all' || inputs.job == 'ubuntu' }}
Expand Down Expand Up @@ -91,7 +106,11 @@ jobs:
restore-keys: ubuntu24-aarch64-gradle-

- name: Build
run: ./gradlew clean build --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew clean build --no-daemon --console=plain 2>&1 | tee ci-logs/build.log

- name: Toolkit jar smoke test
run: |
Expand All @@ -102,6 +121,17 @@ jobs:
java -jar "$JAR" db archive -h
java -jar "$JAR" keystore --help

- name: Upload test diagnostics
if: failure()
uses: actions/upload-artifact@v6
with:
name: tron-test-logs-${{ github.job }}
path: |
**/logs/tron-test.log
ci-logs/*.log
if-no-files-found: warn
retention-days: 7

docker-build-rockylinux:
name: Build rockylinux (JDK 8 / x86_64)
if: ${{ github.event_name == 'pull_request' || inputs.job == 'all' || inputs.job == 'rockylinux' }}
Expand All @@ -113,15 +143,27 @@ jobs:

env:
GRADLE_USER_HOME: /github/home/.gradle
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
LANG: C.utf8
LC_ALL: C.utf8

steps:
- name: Install dependencies (Rocky 8 + JDK8)
run: |
set -euxo pipefail
dnf -y install java-1.8.0-openjdk-devel git wget unzip which jq bc curl glibc-langpack-en
dnf -y groupinstall "Development Tools"
# Rocky 8 already provides CA certificates, JNI runtime libraries, tar and gzip.
# Its built-in C.utf8 locale provides UTF-8 without an extra language pack.
# git-core provides checkout commands; zstd supports actions/cache compression.
# Download more packages concurrently when mirror requests are slow.
dnf -y --setopt=install_weak_deps=False --setopt=max_parallel_downloads=10 install \
java-1.8.0-openjdk-devel git-core zstd
# Set JAVA_HOME so the Gradle wrapper does not need which.
javac_path=$(command -v javac)
javac_real=$(readlink -f "$javac_path")
jdk_bin=$(dirname "$javac_real")
jdk_home=$(dirname "$jdk_bin")
test -x "$jdk_home/bin/java"
test -x "$jdk_home/bin/javac"
printf 'JAVA_HOME=%s\n' "$jdk_home" >> "$GITHUB_ENV"

- name: Checkout code
uses: actions/checkout@v5
Expand All @@ -143,7 +185,11 @@ jobs:
run: ./gradlew --stop || true

- name: Build
run: ./gradlew clean build --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew clean build --no-daemon --console=plain 2>&1 | tee ci-logs/build.log

- name: Toolkit jar smoke test
run: |
Expand All @@ -155,7 +201,22 @@ jobs:
java -jar "$JAR" keystore --help

- name: Test with RocksDB engine
run: ./gradlew :framework:testWithRocksDb --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew :framework:testWithRocksDb --no-daemon --console=plain 2>&1 | tee ci-logs/rocksdb-test.log

- name: Upload test diagnostics
if: failure()
uses: actions/upload-artifact@v6
with:
name: tron-test-logs-${{ github.job }}
path: |
**/logs/tron-test.log
ci-logs/*.log
if-no-files-found: warn
retention-days: 7

docker-build-debian11:
name: Build debian11 (JDK 8 / x86_64)
Expand Down Expand Up @@ -197,7 +258,11 @@ jobs:
debian11-x86_64-gradle-

- name: Build
run: ./gradlew clean build --no-daemon --no-build-cache
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew clean build --no-daemon --no-build-cache --console=plain 2>&1 | tee ci-logs/build.log

- name: Toolkit jar smoke test
run: |
Expand All @@ -209,10 +274,18 @@ jobs:
java -jar "$JAR" keystore --help

- name: Test with RocksDB engine
run: ./gradlew :framework:testWithRocksDb --no-daemon --no-build-cache
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew :framework:testWithRocksDb --no-daemon --no-build-cache --console=plain 2>&1 | tee ci-logs/rocksdb-test.log

- name: Generate module coverage reports
run: ./gradlew jacocoTestReport --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew jacocoTestReport --no-daemon --console=plain 2>&1 | tee ci-logs/coverage.log

- name: Upload PR coverage reports
uses: actions/upload-artifact@v6
Expand All @@ -222,6 +295,17 @@ jobs:
**/build/reports/jacoco/test/jacocoTestReport.xml
if-no-files-found: error

- name: Upload test diagnostics
if: failure()
uses: actions/upload-artifact@v6
with:
name: tron-test-logs-${{ github.job }}
path: |
**/logs/tron-test.log
ci-logs/*.log
if-no-files-found: warn
retention-days: 7

coverage-base:
name: Coverage Base (JDK 8 / x86_64)
if: ${{ github.event_name == 'pull_request' }}
Expand Down Expand Up @@ -260,19 +344,33 @@ jobs:
coverage-base-x86_64-gradle-

- name: Build (base)
id: base_build
# Test failures on the base branch are tolerated: merge-order races can
# leave the base with a pre-existing failing test that is unrelated to
# this PR. The only output we need from this job is the jacoco XML for
# coverage diffing, so we must not let a stale test failure block it.
continue-on-error: true
run: ./gradlew clean build --no-daemon --no-build-cache
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew clean build --no-daemon --no-build-cache --console=plain 2>&1 | tee ci-logs/build.log

- name: Test with RocksDB engine (base)
id: base_rocksdb_test
continue-on-error: true
run: ./gradlew :framework:testWithRocksDb --no-daemon --no-build-cache
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew :framework:testWithRocksDb --no-daemon --no-build-cache --console=plain 2>&1 | tee ci-logs/rocksdb-test.log

- name: Generate module coverage reports (base)
run: ./gradlew jacocoTestReport --no-daemon
shell: bash
run: |
set -euo pipefail
mkdir -p ci-logs
./gradlew jacocoTestReport --no-daemon --console=plain 2>&1 | tee ci-logs/coverage.log

- name: Upload base coverage reports
uses: actions/upload-artifact@v6
Expand All @@ -282,6 +380,18 @@ jobs:
**/build/reports/jacoco/test/jacocoTestReport.xml
if-no-files-found: warn

- name: Upload test diagnostics
# Preserve logs for test failures tolerated by continue-on-error above.
if: ${{ failure() || steps.base_build.outcome == 'failure' || steps.base_rocksdb_test.outcome == 'failure' }}
uses: actions/upload-artifact@v6
with:
name: tron-test-logs-${{ github.job }}
path: |
**/logs/tron-test.log
ci-logs/*.log
if-no-files-found: warn
retention-days: 7

coverage-gate:
name: Coverage Gate
needs: [docker-build-debian11, coverage-base]
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/pr-cancel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
'pr-build.yml',
'codeql.yml',
'integration-test-single-node.yml',
'integration-test-multinode.yml',
];
const headSha = context.payload.pull_request.head.sha;
const prNumber = context.payload.pull_request.number;
Expand Down
10 changes: 5 additions & 5 deletions framework/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id "org.gradle.test-retry" version "1.5.9"
// id "org.gradle.test-retry" version "1.5.9"
id "org.sonarqube" version "2.6"
id "com.gorylenko.gradle-git-properties" version "2.4.1"
}
Expand Down Expand Up @@ -110,10 +110,10 @@ run {
}

def configureTestTask = { Task t ->
t.retry {
maxRetries = 5
maxFailures = 20
}
// t.retry {
// maxRetries = 5
// maxFailures = 20
// }
t.testLogging {
exceptionFormat = 'full'
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class BackupServer implements AutoCloseable {

private BackupManager backupManager;

private Channel channel;
private volatile Channel channel;

private volatile boolean shutdown = false;

Expand Down Expand Up @@ -75,6 +75,12 @@ public void initChannel(NioDatagramChannel ch)

channel = b.bind(port).sync().channel();

// close() may have run while bind was still in progress.
if (shutdown) {
channel.close().sync();
break;
}

logger.info("Backup server started, bind port {}", port);

channel.closeFuture().sync();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.google.common.util.concurrent;

import org.tron.common.math.StrictMathWrapper;

/** Test-only clock for exercising real Guava permit accounting without wall-clock sleeps. */
public final class FakeTimeRateLimiter {

private FakeTimeRateLimiter() {
}

public static RateLimiter create(double permitsPerSecond) {
return RateLimiter.create(permitsPerSecond, new Stopwatch());
}

public static RateLimiter createWithStoredPermit(double permitsPerSecond) {
Stopwatch clock = new Stopwatch();
RateLimiter limiter = RateLimiter.create(permitsPerSecond, clock);
clock.sleepMicrosUninterruptibly((long) StrictMathWrapper.ceil(1_000_000 / permitsPerSecond));
return limiter;
}

private static final class Stopwatch extends RateLimiter.SleepingStopwatch {
private long micros;

@Override
protected long readMicros() {
return micros;
}

@Override
protected void sleepMicrosUninterruptibly(long sleepMicros) {
micros += sleepMicros;
}
}
}
17 changes: 13 additions & 4 deletions framework/src/test/java/org/tron/common/BaseMethodTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
@Slf4j
public abstract class BaseMethodTest {

@Rule
public final VMConfigRule vmConfigRule = new VMConfigRule();

@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();

Expand Down Expand Up @@ -77,11 +80,17 @@ protected void afterInit() {

@After
public final void destroyContext() {
beforeDestroy();
if (context != null) {
context.close(); // triggers appT.shutdown() via TronApplicationContext
try {
beforeDestroy();
} finally {
try {
if (context != null) {
context.close(); // triggers appT.shutdown() via TronApplicationContext
}
} finally {
Args.clearParam();
}
}
Args.clearParam();
}

protected void beforeDestroy() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.tron.common;

import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.tron.common.application.TronApplicationContext;
import org.tron.core.config.args.Args;

public class BaseMethodTestLifecycleTest {

@Test
public void closesContextWhenSubclassCleanupFails() {
BaseMethodTest fixture = new BaseMethodTest() {
@Override
protected void beforeDestroy() {
throw new IllegalStateException("intentional cleanup failure");
}
};
fixture.context = Mockito.mock(TronApplicationContext.class);
Args.setParam(new String[0], TestConstants.TEST_CONF);
try {
IllegalStateException failure = Assert.assertThrows(IllegalStateException.class,
fixture::destroyContext);
Assert.assertEquals("intentional cleanup failure", failure.getMessage());
Mockito.verify(fixture.context).close();
Assert.assertEquals(0, Args.getInstance().getHttpMaxMessageSize());
} finally {
Args.clearParam();
}
}
}
Loading
Loading