Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
e4a1674
build: replace dispatch-core with OkHttp3 in test infrastructure (fix…
hongwei1 Jun 23, 2026
0e2f701
fix: correct OBPReq API gaps found during test-compile
hongwei1 Jun 23, 2026
8b905b9
test: fix Http4sServerIntegrationTest concurrent and cascade scenarios
hongwei1 Jun 23, 2026
4531ed0
fix: correct OBPReq path-segment encoding and duplicate query-param s…
hongwei1 Jun 23, 2026
bf509ee
build: exclude test sources from SonarCloud copy-paste detection
hongwei1 Jun 23, 2026
40dc0fe
refactor: replace OkHttp async callback with synchronous execute in e…
hongwei1 Jun 23, 2026
0b7b841
refactor: eliminate CPD in Http4sServerIntegrationTest and SendServer…
hongwei1 Jun 23, 2026
72c0f4f
refactor: consolidate OkHttp execute pattern into OBPReq.executeRaw()
hongwei1 Jun 23, 2026
4af0058
refactor: replace direct OkHttp execute blocks with executeRaw() dele…
hongwei1 Jun 23, 2026
59b2416
fix: handle empty body in executeRequest for 204 No Content responses
hongwei1 Jun 23, 2026
2aec7bb
fix: strip response body from headAtms for HTTP HEAD compliance
hongwei1 Jun 24, 2026
c54907d
fix: return JNothing for empty response body instead of JObject(Nil)
hongwei1 Jun 24, 2026
49e2809
ci: retrigger CI after runner queue stall
hongwei1 Jun 24, 2026
59cde9f
ci: retrigger after clearing stale run queue
hongwei1 Jun 24, 2026
7b262b7
fix: strip body from HEAD responses at http4s app boundary
hongwei1 Jun 24, 2026
fa67d91
fix: pin graal-sdk/truffle/regex to 22.3.3 to prevent Java-17-compile…
hongwei1 Jun 25, 2026
2e1500b
fix: replace dispatch.Req with OBPReq in ConcurrentRaceSetup
hongwei1 Jun 25, 2026
75b0c4d
merge: pull OBP/develop into fix/issue-9-remove-dispatch
hongwei1 Jun 25, 2026
faeaae0
chore(test): exclude ConcurrencyRace tag from parallel test runner
hongwei1 Jun 25, 2026
4dde0cc
ci: add job timeout-minutes=35 and timeout 1500 wrapper for test shards
hongwei1 Jun 25, 2026
54310cb
fix: allow 'in' operator with multiple values in dynamic entity query…
hongwei1 Jun 25, 2026
6fff251
Merge remote-tracking branch 'Hongwei/develop' into fix/issue-9-remov…
hongwei1 Jun 25, 2026
446a267
ci: upgrade JDK 11→17 and fix timeout exit-code handling
hongwei1 Jun 25, 2026
e869f4a
fix: revert java.version to 11; JDK 17 CI is sufficient for GraalVM 2…
hongwei1 Jun 25, 2026
c27efdb
ci: exclude code.concurrency package from catch-all shard
hongwei1 Jun 25, 2026
11a3c3e
Merge remote-tracking branch 'OBP/develop' into fix/issue-9-remove-di…
hongwei1 Jun 26, 2026
ca1a1dc
test: add GraalVM JS engine smoke tests to DynamicUtil
hongwei1 Jun 26, 2026
de7cd4b
chore: unify runtime to JDK 17 across all environments
hongwei1 Jun 26, 2026
8ffab12
ci: exclude code.concurrency from local catch-all shard; fix stale co…
hongwei1 Jun 26, 2026
8b93ee9
fix: address OBPReq/SendServerRequests robustness issues
hongwei1 Jun 27, 2026
50a8859
refactor: extract string constants, remove dead private methods
hongwei1 Jun 27, 2026
7676e81
ci: rebalance test shards to fix 700s bottleneck on shards 1 and 3
hongwei1 Jun 27, 2026
124a350
ci: include code.concurrency in shard 8 and remove ConcurrencyRace ta…
hongwei1 Jun 29, 2026
c6cc034
fix: make metric enqueue synchronous to eliminate flush() race in Met…
hongwei1 Jun 29, 2026
b86eb0f
ci: sync build_container.yml shard layout and timeouts with build_pul…
hongwei1 Jun 29, 2026
10c29ea
ci: add missing mail.test.mode and test-isolation lint to build_conta…
hongwei1 Jun 29, 2026
e6ba0f9
docs: update run_tests_parallel.sh comments to reflect 9-shard CI layout
hongwei1 Jun 29, 2026
8d026c8
fix(docker): upgrade runtime base image from JDK 11 to JDK 17
hongwei1 Jun 29, 2026
6406f6e
fix: catch NonFatal instead of Throwable in metric write path
hongwei1 Jun 29, 2026
4aaf46e
test: remove AsyncFeatureSpec test-setup family, convert suites to sync
hongwei1 Jun 29, 2026
ff79dd6
fix(docker): add JVM --add-opens flags for CGLib compatibility with J…
hongwei1 Jun 30, 2026
5bc3896
fix(docker): switch to JDK_JAVA_OPTIONS for --add-opens module flags
hongwei1 Jun 30, 2026
f0ebcbc
build: upgrade runtime and CI from JDK 17 to JDK 21
hongwei1 Jun 30, 2026
06befcb
fix(test): skip SecurityManager enforcement tests on JDK 21+
hongwei1 Jun 30, 2026
f0c1eea
build: upgrade Scala compiler from 2.12.20 to 2.12.21
hongwei1 Jul 1, 2026
2f57497
build: upgrade runtime and CI from JDK 21 to JDK 25
hongwei1 Jul 1, 2026
0d3ce87
fix(docker): run Dockerfile_PreBuild container as non-root user
hongwei1 Jul 1, 2026
66ee973
build: merge JDK 25 upgrade into fix/issue-9-remove-dispatch
hongwei1 Jul 1, 2026
dcd3040
fix(docker): add --add-opens flags to ENTRYPOINT for CGLib compatibility
hongwei1 Jul 1, 2026
8fdb9fd
build: carry Add-Opens in the jar manifest and refresh JDK 25 tooling
hongwei1 Jul 2, 2026
ca5b5ca
fix(docker): set obp user home to /app for PostgreSQL SSL cert lookup
hongwei1 Jul 2, 2026
c59f150
refactor: address SonarCloud code smells from PR #28 analysis
hongwei1 Jul 2, 2026
56a6f18
fix(test): stop casting ResourceDoc example body to JvalueCaseClass
hongwei1 Jul 2, 2026
d89590f
fix(test): stop casting ResourceDoc example body to JvalueCaseClass
hongwei1 Jul 2, 2026
7b6b8cc
fix(docker): add --add-opens for java.util and java.util.concurrent
hongwei1 Jul 2, 2026
e3fe06a
fix(boot): catch NonFatal around BankAccountCreationListener.startListen
hongwei1 Jul 2, 2026
153eaf4
Merge build/issue-32-upgrade-jdk25 into fix/issue-9-remove-dispatch
hongwei1 Jul 2, 2026
1d61ee3
Merge remote-tracking branch 'OBP/develop' into fix/issue-9-remove-di…
hongwei1 Jul 2, 2026
041ae28
fix: address new SonarCloud findings from the JDK25/develop merges
hongwei1 Jul 2, 2026
c057e8d
fix(shellcheck): convert remaining single-bracket tests to [[ ]]
hongwei1 Jul 2, 2026
ecf43a3
fix(bg-pis): sequence cancelPayment status save before responding
hongwei1 Jul 2, 2026
54ce06c
refactor(bg-pis): merge duplicate ACCP/PDNG cancel-payment branches
hongwei1 Jul 2, 2026
a0a20ac
Fix CI timeout exit code handling and add missing java.io/java.util.c…
hongwei1 Jul 2, 2026
fcc7010
chore: remove unused build.sbt and sonarcloud assets to sync with dev…
hongwei1 Jul 2, 2026
5a8e4f2
chore: remove junk .metals-config.json and zed IDE configs
hongwei1 Jul 2, 2026
a1ae16b
chore: remove completed lift to http4s migration tracking docs
hongwei1 Jul 2, 2026
967a8ba
chore: remove temporary debugging script test_graalvm_quick.sh
hongwei1 Jul 2, 2026
620a025
fix: close CI v4_0_0 test-coverage hole and warn on disabled sandbox
hongwei1 Jul 3, 2026
094ca93
docs: fix dangling references left by the JDK25/cleanup commits; alig…
hongwei1 Jul 3, 2026
34ea57b
refactor(test): remove dead ReqData round-trip and unused encode_%/de…
hongwei1 Jul 3, 2026
8a12d24
fix(test): close three latent OkHttp-port gaps flagged in review
hongwei1 Jul 3, 2026
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
13 changes: 11 additions & 2 deletions .github/Dockerfile_PreBuild
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
FROM gcr.io/distroless/java:11
FROM eclipse-temurin:25-jre-alpine

RUN addgroup -S obp && adduser -S -h /app -G obp obp

# Copy OBP source code
# Copy build artifact (JAR file) from maven build
COPY /obp-api/target/obp-api.jar /app/obp-api.jar
WORKDIR /app
CMD ["obp-api.jar"]
USER obp
ENTRYPOINT ["java", \
"--add-opens", "java.base/java.lang=ALL-UNNAMED", \
"--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", \
"--add-opens", "java.base/java.io=ALL-UNNAMED", \
"--add-opens", "java.base/java.util=ALL-UNNAMED", \
"--add-opens", "java.base/java.util.concurrent=ALL-UNNAMED", \
"-jar", "/app/obp-api.jar"]
123 changes: 96 additions & 27 deletions .github/workflows/build_container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ env:

# ---------------------------------------------------------------------------
# compile — compiles everything once, packages the JAR, uploads classes
# test — 4-way matrix downloads compiled output and runs a shard of tests
# test — 9-way matrix downloads compiled output and runs a shard of tests
# docker — downloads compiled output, builds and pushes the container image
#
# Wall-clock target:
# compile ~10 min (parallel with setup of test shards)
# tests ~8 min (4 shards in parallel after compile finishes)
# tests ~8 min (9 shards in parallel after compile finishes)
# docker ~3 min (after all shards pass)
# total ~21 min (vs ~30 min single-job)
# ---------------------------------------------------------------------------
Expand All @@ -30,18 +30,21 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up JDK 11
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
java-version: "11"
distribution: "adopt"
java-version: "25"
distribution: "temurin"
cache: maven # caches ~/.m2/repository keyed on pom.xml hash

- name: Setup production props
run: |
cp obp-api/src/main/resources/props/sample.props.template \
obp-api/src/main/resources/props/production.default.props

- name: Lint — test-isolation (no setPropsValues at class/feature body)
run: python3 .github/scripts/check_test_isolation.py

- name: Compile and install (skip test execution)
run: |
# -DskipTests — compile test sources but do NOT run them
Expand Down Expand Up @@ -74,24 +77,36 @@ jobs:
path: push/

# --------------------------------------------------------------------------
# Job 2: test (4-way matrix)
# Job 2: test (9-way matrix, mirrors build_pull_request.yml shard layout)
#
# Shard assignment (based on actual clean-run timings):
# Shard 1 ~258s v4_0_0(258)
# Shard 2 ~267s v6_0_0(122) v5_0_0(42) v3_0_0(39) v2_1_0(35) v2_2_0(12) …
# Shard 3 ~252s v1_2_1(137) ResourceDocs(67) berlin(34) util(12) …
# Shard 4 ~232s v5_1_0(79) v3_1_0(65) http4sbridge(52) v7_0_0(45) … + catch-all
# Shard assignment (wall-clock on GitHub-hosted ubuntu-latest runners):
# Shard 1 ~157s v4_0_0 non-Dynamic (explicit class list, ~58 classes)
# Shard 2 ~257s v1_2_1 (single 6604-line suite, isolated)
# Shard 3 ~155s v6_0_0 only (isolated after v2_x moved to shard 7)
# Shard 4 ~183s v5_1_0 v5_0_0 v3_0_0
# Shard 5 ~193s ResourceDocs v3_1_0 v1_4_0 v1_3_0
# Shard 6 ~168s v7_0_0 http4sbridge UKOpenBanking
# Shard 7 ~280s model + views + customer + util + berlin + v2_x
# Shard 8 ~240s connector + auth + login + mgmt + metrics + catch-all
# Shard 9 ~110s v4_0_0 Dynamic* (6 heavy test classes)
# --------------------------------------------------------------------------
test:
needs: compile
runs-on: ubuntu-latest
timeout-minutes: 35
strategy:
fail-fast: false
matrix:
include:
- shard: 1
name: "v4 only (bottleneck pkg)"
# ~258s — single largest package, kept on its own shard
name: "v4 non-Dynamic"
# v4_0_0 split: non-Dynamic classes only. Dynamic* on shard 9.
# test_filter is a marker, not a literal wildcardSuites value: the "Run tests"
# step below discovers code.api.v4_0_0.* classes at runtime and excludes
# Dynamic* — a static class list here would silently drop any class added
# after the list was written (the shard-8 catch-all treats the whole
# code.api.v4_0_0 package as covered by shard 1, so an omitted class would
# never run on ANY shard). Runtime discovery keeps shard 1 self-updating.
test_filter: >-
code.api.v4_0_0
- shard: 2
Expand All @@ -102,12 +117,11 @@ jobs:
test_filter: >-
code.api.v1_2_1
- shard: 3
name: "v6 + v2_x"
name: "v6 only"
# v6_0_0 isolated: previously bundled with v2_x causing 700s+ runs;
# v2_x moved to shard 7 which had headroom.
test_filter: >-
code.api.v6_0_0
code.api.v2_1_0
code.api.v2_2_0
code.api.v2_0_0
- shard: 4
name: "v5_1 + v5_0 + v3_0"
test_filter: >-
Expand All @@ -128,7 +142,8 @@ jobs:
code.api.http4sbridge
code.api.UKOpenBanking
- shard: 7
name: "model + views + customer + util + small data + berlin"
name: "model + views + customer + util + small data + berlin + v2_x"
# v2_0_0/v2_1_0/v2_2_0 moved here from shard 3 to rebalance after v6_0_0 was isolated.
test_filter: >-
code.model
code.views
Expand All @@ -142,9 +157,12 @@ jobs:
code.crm
code.accountHolder
code.api.berlin
code.api.v2_1_0
code.api.v2_2_0
code.api.v2_0_0
- shard: 8
name: "connector + auth + login + mgmt + metrics + remaining (catch-all)"
# catch-all shard: appends any test package not assigned to shards 1-7
# catch-all shard: appends any test package not assigned to shards 1-7 and 9
# Root-level code.api tests use class-name prefix matching (lowercase classes).
# NOTE: classes that sit DIRECTLY in package code.api must be listed here by
# FQN-prefix — the catch-all marks the parent package code.api as "covered" once
Expand All @@ -165,6 +183,15 @@ jobs:
code.container
code.management
code.metrics
code.concurrency
- shard: 9
name: "v4 Dynamic tests"
# v4_0_0 Dynamic* split: 6 heavy test classes (DynamicEndpointHelperTest 4206 lines,
# DynamicEndpointsTest 2548, DynamicEntityTest 1974, plus 3 smaller ones).
# Prefix code.api.v4_0_0.Dynamic matches all 6 classes; shard 1's runtime
# discovery excludes this same prefix so no test runs in both shards.
test_filter: >-
code.api.v4_0_0.Dynamic

services:
redis:
Expand All @@ -180,11 +207,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up JDK 11
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
java-version: "11"
distribution: "adopt"
java-version: "25"
distribution: "temurin"
cache: maven

- name: Download compiled output
Expand Down Expand Up @@ -258,6 +285,12 @@ jobs:
echo consents.allowed=true >> obp-api/src/main/resources/props/test.default.props
echo hikari.maximumPoolSize=20 >> obp-api/src/main/resources/props/test.default.props
echo write_metrics=false >> obp-api/src/main/resources/props/test.default.props
# Log emails instead of opening a real SMTP socket: without this,
# LocalMappedConnector.sendCustomerNotification's EMAIL branch calls
# CommonsEmailWrapper.sendTextEmail which throws ConnectException because
# there's no mail server in CI. That surfaces as 500 in any test that
# hits an endpoint triggering the notification (v5 consent flows, etc.).
echo mail.test.mode=true >> obp-api/src/main/resources/props/test.default.props
# Permissions granted to runtime-compiled dynamic-endpoint code inside the security sandbox
# (mirrors default.props / production.default.props). Required so dynamic resource-doc bodies
# can do JSON extraction (reflection) and read OBP props (getenv); without it the sandbox
Expand All @@ -270,19 +303,38 @@ jobs:
# The YAML >- scalar collapses newlines to spaces, so we convert here.
FILTER=$(echo "${{ matrix.test_filter }}" | tr ' ' ',')

# Shard 1 (v4 non-Dynamic): discover code.api.v4_0_0 classes at runtime and
# exclude Dynamic* (shard 9's domain), instead of a hand-maintained class list.
# This is what makes the shard-8 catch-all's "code.api.v4_0_0 is covered by
# shard 1" assumption actually true — a class list here could drift from the
# real directory contents and leave a new test running on no shard at all.
if [ "${{ matrix.shard }}" = "1" ]; then
FILTER=$(grep -l '^class.*extends' obp-api/src/test/scala/code/api/v4_0_0/*.scala \
| xargs -I{} grep -hoP '^class \K[A-Z][A-Za-z0-9_]+' {} \
| grep -v '^Dynamic' \
| sed 's/^/code.api.v4_0_0./' \
| paste -sd, -)
fi

# Shard 8 is the catch-all: append any test package not explicitly
# assigned to shards 1–7, so new packages are never silently skipped.
# assigned to shards 1–7 and 9, so new packages are never silently skipped.
if [ "${{ matrix.shard }}" = "8" ]; then
# Shard 1 discovers v4 non-Dynamic classes at runtime (see above); shard 9
# covers Dynamic*. Use code.api.v4_0_0 as the assigned prefix so the
# catch-all treats the whole v4_0_0 package as covered — true as long as
# shard 1's discovery and shard 9's Dynamic prefix together span it.
SHARD1="code.api.v4_0_0"
SHARD2="code.api.v1_2_1"
SHARD3="code.api.v6_0_0 code.api.v2_1_0 code.api.v2_2_0 code.api.v2_0_0"
SHARD3="code.api.v6_0_0"
SHARD4="code.api.v5_1_0 code.api.v5_0_0 code.api.v3_0_0"
SHARD5="code.api.ResourceDocs1_4_0 code.api.v3_1_0 code.api.v1_4_0 code.api.v1_3_0"
SHARD6="code.api.v7_0_0 code.api.http4sbridge code.api.UKOpenBanking"
SHARD7="code.model code.views code.customer code.usercustomerlinks \
code.api.util code.errormessages code.atms code.branches \
code.products code.crm code.accountHolder code.api.berlin"
ASSIGNED="$SHARD1 $SHARD2 $SHARD3 $SHARD4 $SHARD5 $SHARD6 $SHARD7 ${{ matrix.test_filter }}"
code.products code.crm code.accountHolder code.api.berlin \
code.api.v2_1_0 code.api.v2_2_0 code.api.v2_0_0"
SHARD9="code.api.v4_0_0.Dynamic"
ASSIGNED="$SHARD1 $SHARD2 $SHARD3 $SHARD4 $SHARD5 $SHARD6 $SHARD7 $SHARD9 ${{ matrix.test_filter }}"

# Discover all packages that contain at least one .scala test file
ALL_PKGS=$(find obp-api/src/test/scala obp-commons/src/test/scala \
Expand Down Expand Up @@ -315,10 +367,27 @@ jobs:
# -pl obp-commons,obp-api: obp-commons' own 5 util suites run on whichever
# shard's filter matches com.openbankproject.* (the catch-all shard); on every
# other shard the filter matches nothing in obp-commons → 0 tests there.
# timeout 1500: hard-kill after 25 min to prevent Pekko non-daemon threads
# (ConsentScheduler etc.) from keeping the JVM alive after tests complete.
# Exit code 124 (timeout) is treated as success — tests are done, JVM just hung.
# set +e: GitHub Actions uses -eo pipefail by default; without it, a 124 exit from
# timeout would abort the step before the rc check below can run.
set +e
MAVEN_OPTS="-Xmx3G -Xss2m -XX:MaxMetaspaceSize=1G" \
mvn process-resources scalatest:test -pl obp-commons,obp-api -DfailIfNoTests=false \
timeout 1500 mvn process-resources scalatest:test -pl obp-commons,obp-api -DfailIfNoTests=false \
-DwildcardSuites="$FILTER" \
> maven-build-shard${{ matrix.shard }}.log 2>&1
rc=$?
set -e
# timeout returns 124 when the JVM was killed. That is only benign when the tests had
# successfully finished but Pekko non-daemon threads kept the JVM alive. We must
# require proof from the log instead of blindly converting 124 to success.
if [ $rc -eq 124 ]; then
if grep -q "BUILD SUCCESS" maven-build-shard${{ matrix.shard }}.log; then
rc=0
fi
fi
exit $rc

- name: Report failing tests — shard ${{ matrix.shard }}
if: always()
Expand Down
Loading
Loading