FINERACT-2181: Use matrix jobs via Github Actions to improve performance

This commit is contained in:
Adam Saghy
2025-07-02 10:01:37 +02:00
committed by Arnold Gálovics
parent dc2101bc21
commit 70eb2add0d
28 changed files with 924 additions and 437 deletions
+111
View File
@@ -0,0 +1,111 @@
name: Fineract Build & Cucumber tests (without E2E tests)
on: [push, pull_request]
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- task: build-core
job_type: main
- task: cucumber
job_type: main
- task: build-progressive-loan
job_type: progressive-loan
env:
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- name: Setup Gradle and Validate Wrapper
uses: gradle/actions/setup-gradle@v4.4.1
with:
validate-wrappers: true
- name: Run Gradle Task
if: matrix.job_type == 'main'
run: |
case "${{ matrix.task }}" in
build-core)
./gradlew --no-daemon build -x test -x cucumber -x doc
;;
cucumber)
./gradlew --no-daemon cucumber -x :fineract-e2e-tests-runner:cucumber -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
esac
- name: Build and Test Progressive Loan
if: matrix.job_type == 'progressive-loan'
run: |
# Build the JAR
./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
# Store the JAR filename in an environment variable
EMBEDDABLE_JAR_FILE=$(ls fineract-progressive-loan-embeddable-schedule-generator/build/libs/*-all.jar | head -n 1)
echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV
echo "JAR file: $EMBEDDABLE_JAR_FILE"
# Run unit tests
./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:test
# Build and run sample application
mkdir -p sample-app
javac -cp "$EMBEDDABLE_JAR_FILE" -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main
java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main 25
- name: Archive test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.task }}
path: |
**/build/reports/
**/fineract-progressive-loan-embeddable-schedule-generator/build/reports/
if-no-files-found: ignore
retention-days: 5
- name: Archive Progressive Loan JAR
if: matrix.job_type == 'progressive-loan' && always()
uses: actions/upload-artifact@v4
with:
name: progressive-loan-jar
path: ${{ env.EMBEDDABLE_JAR_FILE }}
retention-days: 5
if-no-files-found: ignore
- name: Archive server logs
if: always()
uses: actions/upload-artifact@v4
with:
name: server-logs-${{ matrix.task }}
path: '**/build/cargo/'
retention-days: 5
@@ -1,31 +0,0 @@
name: Fineract Docker build - PostgreSQL
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the Standalone Stack
run: docker compose -f docker-compose-postgresql.yml up -d
- name: Check the stack
run: docker ps
- name: Check health
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
- name: Check info
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
@@ -1,31 +1,53 @@
name: Fineract Docker build - MariaDB
name: Fineract Docker Builds
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
strategy:
matrix:
db_type: [mariadb, postgresql]
include:
- db_type: mariadb
compose_file: docker-compose.yml
check_worker_health: true
- db_type: postgresql
compose_file: docker-compose-postgresql.yml
check_worker_health: false
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the stack
run: docker compose -f docker-compose.yml up -d
- name: Start the ${{ matrix.db_type }} stack
run: docker compose -f ${{ matrix.compose_file }} up -d
- name: Check the stack
run: docker ps
- name: Check health
- name: Check health Manager
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
- name: Check info
- name: Check info Manager
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
+165
View File
@@ -0,0 +1,165 @@
name: Fineract E2E Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
name: E2E Tests (Shard ${{ matrix.shard_index }} of ${{ matrix.total_shards }})
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
# Define the number of shards (1-based indexing)
shard_index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
total_shards: [10]
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
BASE_URL: https://localhost:8443
TEST_USERNAME: mifos
TEST_PASSWORD: password
TEST_STRONG_PASSWORD: A1b2c3d4e5f$
TEST_TENANT_ID: default
INITIALIZATION_ENABLED: true
EVENT_VERIFICATION_ENABLED: true
ACTIVEMQ_BROKER_URL: tcp://localhost:61616
ACTIVEMQ_TOPIC_NAME: events
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4.4.1
- name: Make scripts executable
run: chmod +x scripts/split-features.sh
- name: Split feature files into shards
id: split-features
run: |
./scripts/split-features.sh ${{ matrix.total_shards }} ${{ matrix.shard_index }}
echo "Shard ${{ matrix.shard_index }} feature files:"
cat feature_shard_${{ matrix.shard_index }}.txt
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the Fineract stack
run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d
- name: Check the stack
run: docker ps
- name: Wait for Manager to be ready
run: |
# Wait for the container to be running
echo "Waiting for Manager container to be ready..."
timeout 300 bash -c 'until docker ps --filter "health=healthy" --filter "name=fineract" --format "{{.Status}}" | grep -q "healthy"; do
if docker ps --filter "name=fineract" --format "{{.Status}}" | grep -q "unhealthy"; then
echo "Container is unhealthy. Stopping..."
docker ps -a
docker logs $(docker ps -q --filter name=fineract) || true
exit 1
fi
echo "Waiting for Manager to be ready..."
sleep 5
done'
# Check the health endpoint
echo "Checking Manager health endpoint..."
curl -f -k --retry 30 --retry-all-errors --connect-timeout 10 --retry-delay 10 \
https://localhost:8443/fineract-provider/actuator/health
- name: Execute tests for shard ${{ matrix.shard_index }}
run: |
# Read feature files from the shard file
FEATURES=$(tr '\n' ',' < "feature_shard_${{ matrix.shard_index }}.txt" | sed 's/,$//')
if [ -z "$FEATURES" ]; then
echo "No features to test in this shard. Skipping..."
exit 0
fi
# Create a directory for individual allure results
mkdir -p "allure-results-shard-${{ matrix.shard_index }}"
# Read each feature file path and run tests one by one
while IFS= read -r feature_file || [ -n "$feature_file" ]; do
# Skip empty lines
[ -z "$feature_file" ] && continue
# Create a safe filename for the results
safe_name=$(echo "$feature_file" | tr '/' '-' | tr ' ' '_')
echo "Testing feature: $feature_file"
# Run tests with individual allure results directory
./gradlew --no-daemon --console=plain \
:fineract-e2e-tests-runner:cucumber \
-Pcucumber.features="$feature_file" \
-Dallure.results.directory="allure-results-shard-${{ matrix.shard_index }}/$safe_name" \
allureReport || echo "Test failed for $feature_file, continuing with next feature..."
# Copy the results to a merged directory
if [ -d "allure-results-shard-${{ matrix.shard_index }}/$safe_name" ]; then
cp -r "allure-results-shard-${{ matrix.shard_index }}/$safe_name/." "allure-results-merged/" || true
fi
done < "feature_shard_${{ matrix.shard_index }}.txt"
# Generate individual report for this shard
if [ -d "allure-results-merged" ]; then
mkdir -p "allure-report-shard-${{ matrix.shard_index }}"
allure generate "allure-results-merged" --clean -o "allure-report-shard-${{ matrix.shard_index }}" || echo "Failed to generate Allure report for shard ${{ matrix.shard_index }}"
fi
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-results-shard-${{ matrix.shard_index }}
path: |
allure-results-shard-${{ matrix.shard_index }}
allure-results-merged
**/build/allure-results
**/build/reports/tests/test
**/build/test-results/test
retention-days: 5
- name: Upload Allure Report
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-report-shard-${{ matrix.shard_index }}
path: allure-report-shard-${{ matrix.shard_index }}
retention-days: 5
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: logs-shard-${{ matrix.shard_index }}
path: |
**/build/reports/tests/
**/logs/
**/out/
retention-days: 5
- name: Clean up
if: always()
run: |
docker compose -f docker-compose-postgresql-test-activemq.yml down -v
docker system prune -f
@@ -1,47 +0,0 @@
name: Fineract Build Progressive Loan Embeddable Jar & Test with a Sample Application
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build Embeddable Jar
run: ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
- name: Pick up the JAR filename
run: |
EMBEDDABLE_JAR_FILE=(`ls fineract-progressive-loan-embeddable-schedule-generator/build/libs/*-all.jar | head -n 1`)
echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV
- name: Run unit tests
run: ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:test
- name: Build Sample Application
run: |
mkdir sample-app
javac -cp $EMBEDDABLE_JAR_FILE -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
env:
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
- name: Run Schedule Generator Sample Application
run: |
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main 25
env:
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
- name: Archive test results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: test-results
path: |
build/reports/
fineract-progressive-loan-embeddable-schedule-generator/build/reports/
+108 -58
View File
@@ -1,92 +1,142 @@
name: Fineract Build & Test - MariaDB
name: Fineract Cargo & Unit- & Integration tests - MariaDB
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
test:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5, test-twofactor, test-oauth2]
services:
mariad:
image: mariadb:11.5.2
ports:
- 3306:3306
env:
MARIADB_ROOT_PASSWORD: mysql
options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
mariadb:
image: mariadb:11.5.2
ports:
- 3306:3306
env:
MARIADB_ROOT_PASSWORD: mysql
options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
env:
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- name: Setup Gradle and Validate Wrapper
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4.4.1
with:
validate-wrappers: true
- name: Verify MariaDB connection
run: |
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
sleep 1
done
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
sleep 1
done
- name: Initialise databases
run: |
./gradlew --no-daemon -q createDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createDB -PdbName=fineract_default
./gradlew --no-daemon -q createDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createDB -PdbName=fineract_default
- name: Start LocalStack
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
run: |
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
sleep 10
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
echo "LocalStack initialization complete"
- name: Build & Test
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
- name: Generate test class list (only for test-core-X)
if: startsWith(matrix.task, 'test-core-')
run: |
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test -x :fineract-e2e-tests-runner:test
./gradlew --no-daemon --console=plain :twofactor-tests:test
./gradlew --no-daemon --console=plain :oauth2-tests:test
chmod +x scripts/split-tests.sh
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
./scripts/split-tests.sh 5 $SHARD_INDEX
cat "shard-tests_${SHARD_INDEX}.txt"
- name: Run Gradle Task
run: |
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
case "${{ matrix.task }}" in
test-twofactor)
./gradlew --no-daemon :twofactor-tests:test -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-oauth2)
./gradlew --no-daemon :oauth2-tests:test -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-core-*)
echo "Grouping test classes by module..."
declare -A module_tests
while IFS=, read -r module class; do
module_tests["$module"]+="$class "
done < "shard-tests_${SHARD_INDEX}.txt"
for module in "${!module_tests[@]}"; do
echo "Running tests in $module:"
for class in ${module_tests[$module]}; do
echo " - $class"
done
# Build test args
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
# Run test task for this module
./gradlew "$module:test" $test_args -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
done
;;
esac
- name: Archive test results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
build/reports/
integration-tests/build/reports/
twofactor-tests/build/reports/
oauth2-tests/build/reports/
name: test-results-${{ matrix.task }}
path: '**/build/reports/'
retention-days: 5
- name: Archive server logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: server-logs
path: |
integration-tests/build/cargo/
twofactor-tests/build/cargo/
oauth2-tests/build/cargo/
name: server-logs-${{ matrix.task }}
path: '**/build/cargo/'
retention-days: 5
+109 -59
View File
@@ -1,92 +1,142 @@
name: Fineract Build & Test - MySQL
name: Fineract Cargo & Unit- & Integration tests - MySQL
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
test:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5, test-twofactor, test-oauth2]
services:
mariad:
image: mysql:9.1
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: mysql
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
mysql:
image: mysql:9.1
ports:
- 3306:3306
env:
MYSQL_ROOT_PASSWORD: mysql
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
env:
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- name: Setup Gradle and Validate Wrapper
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4.4.1
with:
validate-wrappers: true
- name: Verify MariaDB connection
- name: Verify MySQL connection
run: |
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
sleep 1
done
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
sleep 1
done
- name: Initialise databases
run: |
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_default
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_default
- name: Start LocalStack
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
run: |
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
sleep 10
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
echo "LocalStack initialization complete"
- name: Build & Test
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
- name: Generate test class list (only for test-core-X)
if: startsWith(matrix.task, 'test-core-')
run: |
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test -x :fineract-e2e-tests-runner:test -PdbType=mysql
./gradlew --no-daemon --console=plain :twofactor-tests:test -PdbType=mysql
./gradlew --no-daemon --console=plain :oauth2-tests:test -PdbType=mysql
chmod +x scripts/split-tests.sh
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
./scripts/split-tests.sh 5 $SHARD_INDEX
cat "shard-tests_${SHARD_INDEX}.txt"
- name: Run Gradle Task
run: |
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
case "${{ matrix.task }}" in
test-twofactor)
./gradlew --no-daemon :twofactor-tests:test -PdbType=mysql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-oauth2)
./gradlew --no-daemon :oauth2-tests:test -PdbType=mysql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-core-*)
echo "Grouping test classes by module..."
declare -A module_tests
while IFS=, read -r module class; do
module_tests["$module"]+="$class "
done < "shard-tests_${SHARD_INDEX}.txt"
for module in "${!module_tests[@]}"; do
echo "Running tests in $module:"
for class in ${module_tests[$module]}; do
echo " - $class"
done
# Build test args
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
# Run test task for this module
./gradlew "$module:test" $test_args -PdbType=mysql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
done
;;
esac
- name: Archive test results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
build/reports/
integration-tests/build/reports/
twofactor-tests/build/reports/
oauth2-tests/build/reports/
name: test-results-${{ matrix.task }}
path: '**/build/reports/'
retention-days: 5
- name: Archive server logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: server-logs
path: |
integration-tests/build/cargo/
twofactor-tests/build/cargo/
oauth2-tests/build/cargo/
name: server-logs-${{ matrix.task }}
path: '**/build/cargo/'
retention-days: 5
+109 -59
View File
@@ -1,93 +1,143 @@
name: Fineract Build & Test - PostgreSQL
name: Fineract Cargo & Unit- & Integration tests - PostgreSQL
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
test:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5, test-twofactor, test-oauth2]
services:
postgresql:
image: postgres:17.4
ports:
- 5432:5432
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: postgres
options: --health-cmd="pg_isready -q -d postgres -U root" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
postgresql:
image: postgres:17.4
ports:
- 5432:5432
env:
POSTGRES_USER: root
POSTGRES_PASSWORD: postgres
options: --health-cmd="pg_isready -q -d postgres -U root" --health-interval=5s --health-timeout=2s --health-retries=3
mock-oauth2-server:
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
ports:
- 9000:9000
env:
SERVER_PORT: 9000
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
env:
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
TZ: Asia/Kolkata
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
- name: Setup Gradle and Validate Wrapper
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4.4.1
with:
validate-wrappers: true
- name: Verify PostgreSQL connection
run: |
while ! pg_isready -d postgres -U root -h 127.0.0.1 -p 5432 ; do
sleep 1
done
while ! pg_isready -d postgres -U root -h 127.0.0.1 -p 5432 ; do
sleep 1
done
- name: Initialise databases
run: |
./gradlew --no-daemon -q createPGDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createPGDB -PdbName=fineract_default
./gradlew --no-daemon -q createPGDB -PdbName=fineract_tenants
./gradlew --no-daemon -q createPGDB -PdbName=fineract_default
- name: Start LocalStack
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
run: |
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
sleep 10
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
echo "LocalStack initialization complete"
- name: Build & Test
env:
AWS_ENDPOINT_URL: http://localhost:4566
AWS_ACCESS_KEY_ID: localstack
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
FINERACT_REPORT_EXPORT_S3_ENABLED: true
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
- name: Generate test class list (only for test-core-X)
if: startsWith(matrix.task, 'test-core-')
run: |
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test -x :fineract-e2e-tests-runner:test -PdbType=postgresql
./gradlew --no-daemon --console=plain :twofactor-tests:test -PdbType=postgresql
./gradlew --no-daemon --console=plain :oauth2-tests:test -PdbType=postgresql
chmod +x scripts/split-tests.sh
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
./scripts/split-tests.sh 5 $SHARD_INDEX
cat "shard-tests_${SHARD_INDEX}.txt"
- name: Run Gradle Task
run: |
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
case "${{ matrix.task }}" in
test-twofactor)
./gradlew --no-daemon :twofactor-tests:test -PdbType=postgresql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-oauth2)
./gradlew --no-daemon :oauth2-tests:test -PdbType=postgresql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
;;
test-core-*)
echo "Grouping test classes by module..."
declare -A module_tests
while IFS=, read -r module class; do
module_tests["$module"]+="$class "
done < "shard-tests_${SHARD_INDEX}.txt"
for module in "${!module_tests[@]}"; do
echo "Running tests in $module:"
for class in ${module_tests[$module]}; do
echo " - $class"
done
# Build test args
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
# Run test task for this module
./gradlew "$module:test" $test_args -PdbType=postgresql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
done
;;
esac
- name: Archive test results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: test-results
path: |
build/reports/
integration-tests/build/reports/
twofactor-tests/build/reports/
oauth2-tests/build/reports/
name: test-results-${{ matrix.task }}
path: '**/build/reports/'
retention-days: 5
- name: Archive server logs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: server-logs
path: |
integration-tests/build/cargo/
twofactor-tests/build/cargo/
oauth2-tests/build/cargo/
name: server-logs-${{ matrix.task }}
path: '**/build/cargo/'
retention-days: 5
-41
View File
@@ -1,41 +0,0 @@
name: Fineract Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the Fineract stack
run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d
- name: Check the stack
run: docker ps
- name: Check health Manager
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
- name: Execute tests
env:
BASE_URL: https://localhost:8443
TEST_USERNAME: mifos
TEST_PASSWORD: password
TEST_STRONG_PASSWORD: A1b2c3d4e5f$
TEST_TENANT_ID: default
INITIALIZATION_ENABLED: true
EVENT_VERIFICATION_ENABLED: true
ACTIVEMQ_BROKER_URL: tcp://localhost:61616
ACTIVEMQ_TOPIC_NAME: events
run: ./gradlew --no-daemon --console=plain :fineract-e2e-tests-runner:cucumber --tags 'not @Skip' allureReport
-37
View File
@@ -1,37 +0,0 @@
name: Fineract Kafka Smoke
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the Kafka Stack
run: docker compose -f docker-compose-postgresql-kafka.yml up --scale fineract-worker=1 -d
- name: Check the stack
run: docker ps
- name: Check health Manager
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
- name: Check health Worker1
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health
- name: Check info Manager
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
- name: Check info Worker1
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 ))
- name: Run Smoke Test with Remote COB
run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled
@@ -1,37 +1,61 @@
name: Fineract ActiveMQ Smoke
name: Fineract Messaging Smoke Tests
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
smoke-test:
name: Smoke Test with ${{ matrix.messaging }}
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- messaging: ActiveMQ
compose_file: docker-compose-postgresql-activemq.yml
- messaging: Kafka
compose_file: docker-compose-postgresql-kafka.yml
env:
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
IMAGE_NAME: fineract
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0
- name: Set up JDK 21
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
with:
java-version: '21'
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Build the image
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
- name: Start the ActiveMQ Stack
run: docker compose -f docker-compose-postgresql-activemq.yml up --scale fineract-worker=1 -d
- name: Start the ${{ matrix.messaging }} Stack
run: docker compose -f ${{ matrix.compose_file }} up --scale fineract-worker=1 -d
- name: Check the stack
run: docker ps
- name: Check health Manager
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
- name: Check health Worker1
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health
- name: Check info Manager
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
- name: Check info Worker1
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 ))
- name: Run Smoke Test with Remote COB
run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled