FINERACT-2181: Use matrix jobs via Github Actions to improve performance
This commit is contained in:
committed by
Arnold Gálovics
parent
dc2101bc21
commit
70eb2add0d
@@ -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 ))
|
||||
@@ -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/
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
+2
-1
@@ -341,7 +341,8 @@ allprojects {
|
||||
"**/generated/**/*MapperImpl.java",
|
||||
'**/META-INF/fineract-test.config',
|
||||
// Apache-specific GitHub metadata settings file
|
||||
'/.asf.yaml'
|
||||
'/.asf.yaml',
|
||||
'**/*.sh'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+5
-2
@@ -33,8 +33,11 @@ public interface OfficeDataMapper {
|
||||
if (hierarchy == null) {
|
||||
nameDecorated = "";
|
||||
} else {
|
||||
nameDecorated = hierarchy.substring(0, (hierarchy.length() - hierarchy.replace(".", "").length() - 1) * 4)
|
||||
+ Optional.ofNullable(office.getName()).orElse("");
|
||||
long count = hierarchy.chars().filter(c -> c == '.').count();
|
||||
if (count > 0) {
|
||||
count--;
|
||||
}
|
||||
nameDecorated = "....".repeat((int) count) + Optional.ofNullable(office.getName()).orElse("");
|
||||
}
|
||||
return new OfficeData(office.getId(), office.getName(), nameDecorated, office.getExternalId(), office.getOpeningDate(),
|
||||
office.getHierarchy(), office.getParent() != null ? office.getParent().getId() : null,
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ public class JobService {
|
||||
.pollInterval(Duration.ofMillis(jobPollingProperties.getIntervalInMillis())) //
|
||||
.pollDelay(Duration.ofMillis(jobPollingProperties.getDelayInMillis())) //
|
||||
.until(() -> {
|
||||
log.info("Waiting for job {} to finish", jobName);
|
||||
log.debug("Waiting for job {} to finish", jobName);
|
||||
Long jobId = jobResolver.resolve(job);
|
||||
Response<GetJobsResponse> getJobsResponse = schedulerJobApi.retrieveOne5(jobId).execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(getJobsResponse);
|
||||
|
||||
+3
-3
@@ -947,10 +947,10 @@ public class BatchApiStepDef extends AbstractStepDef {
|
||||
|
||||
if (batchResponseList.isSuccessful() && batchResponseList.body() != null && !batchResponseList.body().isEmpty()) {
|
||||
BatchResponse response = batchResponseList.body().get(0);
|
||||
log.info("Batch charge-off API status code: {}", response.getStatusCode());
|
||||
log.info("Batch charge-off API response body: {}", response.getBody());
|
||||
log.debug("Batch charge-off API status code: {}", response.getStatusCode());
|
||||
log.debug("Batch charge-off API response body: {}", response.getBody());
|
||||
} else {
|
||||
log.info("Batch charge-off API call failed or returned empty response");
|
||||
log.warn("Batch charge-off API call failed or returned empty response");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -4029,7 +4029,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
ErrorHelper.checkSuccessfulApiCall(transactionsByLoanIdFiltered);
|
||||
|
||||
List<GetLoansLoanIdTransactionsTransactionIdResponse> transactions = transactionsByLoanIdFiltered.body().getContent();
|
||||
log.info("Filtered transactions: {}", transactions);
|
||||
log.debug("Filtered transactions: {}", transactions);
|
||||
|
||||
List<String> excludedTypesList = Arrays.stream(excludedTypes.toLowerCase().split(",")).map(String::trim)
|
||||
.collect(Collectors.toList());
|
||||
@@ -4052,7 +4052,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
ErrorHelper.checkSuccessfulApiCall(transactionsByLoanExternalIdFiltered);
|
||||
|
||||
List<GetLoansLoanIdTransactionsTransactionIdResponse> transactions = transactionsByLoanExternalIdFiltered.body().getContent();
|
||||
log.info("Filtered transactions: {}", transactions);
|
||||
log.debug("Filtered transactions: {}", transactions);
|
||||
|
||||
List<String> excludedTypesList = Arrays.stream(excludedTypes.toLowerCase().split(",")).map(String::trim)
|
||||
.collect(Collectors.toList());
|
||||
@@ -4514,7 +4514,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
|
||||
// Get current business date to ensure we're not creating backdated transactions
|
||||
String currentBusinessDate = businessDateHelper.getBusinessDate();
|
||||
log.info("Current business date: {}, Transaction date: {}", currentBusinessDate, transactionDate);
|
||||
log.debug("Current business date: {}, Transaction date: {}", currentBusinessDate, transactionDate);
|
||||
|
||||
final Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
|
||||
@@ -4530,7 +4530,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
testContext().set(TestContextKey.LOAN_CAPITALIZED_INCOME_ADJUSTMENT_RESPONSE, adjustmentResponse);
|
||||
ErrorHelper.checkSuccessfulApiCall(adjustmentResponse);
|
||||
|
||||
log.info("Capitalized Income Adjustment created: Transaction ID {}", adjustmentResponse.body().getResourceId());
|
||||
log.debug("Capitalized Income Adjustment created: Transaction ID {}", adjustmentResponse.body().getResourceId());
|
||||
}
|
||||
|
||||
@And("Admin adds capitalized income adjustment with {string} payment type to the loan on {string} with {string} EUR trn amount with {string} date for capitalized income")
|
||||
@@ -4554,7 +4554,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
testContext().set(TestContextKey.LOAN_CAPITALIZED_INCOME_ADJUSTMENT_RESPONSE, adjustmentResponse);
|
||||
ErrorHelper.checkSuccessfulApiCall(adjustmentResponse);
|
||||
|
||||
log.info("Capitalized Income Adjustment created: Transaction ID {}", adjustmentResponse.body().getResourceId());
|
||||
log.debug("Capitalized Income Adjustment created: Transaction ID {}", adjustmentResponse.body().getResourceId());
|
||||
}
|
||||
|
||||
@And("Admin adds invalid capitalized income adjustment with {string} payment type to the loan on {string} with {string} EUR transaction amount")
|
||||
@@ -4565,7 +4565,7 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
|
||||
// Get current business date to ensure we're not creating backdated transactions
|
||||
String currentBusinessDate = businessDateHelper.getBusinessDate();
|
||||
log.info("Current business date: {}, Transaction date: {}", currentBusinessDate, transactionDate);
|
||||
log.debug("Current business date: {}, Transaction date: {}", currentBusinessDate, transactionDate);
|
||||
|
||||
final Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
|
||||
|
||||
@@ -81,13 +81,23 @@ tasks.named('cucumber').get().finalizedBy 'allureReport'
|
||||
tasks.named('cucumber').get().dependsOn 'spotlessCheck'
|
||||
|
||||
cucumber {
|
||||
tags = 'not @ignore'
|
||||
main = 'io.cucumber.core.cli.Main'
|
||||
shorten = 'argfile'
|
||||
plugin = [
|
||||
'pretty',
|
||||
'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm'
|
||||
]
|
||||
// Use -Pcucumber.features=... if passed, otherwise default
|
||||
if (project.hasProperty("cucumber.features")) {
|
||||
featurePath = project.getProperty("cucumber.features")
|
||||
} else {
|
||||
featurePath = "src/test/resources/features";
|
||||
}
|
||||
|
||||
tags = 'not @Skip'
|
||||
if (project.hasProperty("cucumber.tags")) {
|
||||
tags = [project.getProperty("cucumber.tags")]
|
||||
}
|
||||
|
||||
if (project.hasProperty("cucumber.name")) {
|
||||
name = project.getProperty("cucumber.name")
|
||||
}
|
||||
|
||||
plugin = ['pretty', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm']
|
||||
}
|
||||
|
||||
allure {
|
||||
|
||||
+3
@@ -86,6 +86,9 @@ public class AccrualsOnLoanClosureTest extends BaseLoanIntegrationTest {
|
||||
transaction(800.0, "Disbursement", "22 April 2024", 800.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(820.0, "Repayment", "25 April 2024", 0.0, 800.0, 0.0, 0.0, 20.0, 0.0, 0.0),
|
||||
transaction(20.0, "Accrual", "25 April 2024", 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0));
|
||||
|
||||
globalConfigurationHelper.updateGlobalConfiguration(CHARGE_ACCRUAL_DATE,
|
||||
new PutGlobalConfigurationsRequest().stringValue("due-date"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -25,14 +25,24 @@ import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.response.Response;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@Slf4j
|
||||
public class ActuatorIntegrationTest {
|
||||
|
||||
private static final String INFO_URL = "/fineract-provider/actuator/info";
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActuatorGitBuildInfo() {
|
||||
log.info(INFO_URL);
|
||||
Response response = RestAssured.given().headers("Content-Type", ContentType.JSON, "Accept", ContentType.JSON).when().get(INFO_URL)
|
||||
.then().contentType(ContentType.JSON).extract().response();
|
||||
|
||||
|
||||
+4
-6
@@ -168,9 +168,8 @@ public class DelinquencyAndChargebackIntegrationTest extends BaseLoanIntegration
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
log.info("Current Business date {}", businessDate);
|
||||
|
||||
// Run the Loan COB Job
|
||||
final String jobName = "Loan COB";
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
@@ -293,9 +292,8 @@ public class DelinquencyAndChargebackIntegrationTest extends BaseLoanIntegration
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, businessDate);
|
||||
log.info("Current Business date {}", businessDate);
|
||||
|
||||
// Run the Loan COB Job
|
||||
final String jobName = "Loan COB";
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
|
||||
+45
-65
@@ -76,7 +76,6 @@ import org.apache.fineract.integrationtests.common.CommonConstants;
|
||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.CobHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
||||
@@ -867,9 +866,8 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
assertTrue(jobBusinessStepConfigData.getBusinessSteps().stream().anyMatch(
|
||||
businessStep -> BusinessConfigurationApiTest.LOAN_DELINQUENCY_CLASSIFICATION.equals(businessStep.getStepName())));
|
||||
|
||||
// Run first time the Loan COB Job
|
||||
final String jobName = "Loan COB";
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have not a delinquency classification
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
@@ -885,13 +883,11 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
}
|
||||
|
||||
// Move the Business date to get older the loan and to have an overdue loan
|
||||
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate;
|
||||
bussinesLocalDate = bussinesLocalDate.plusDays(3);
|
||||
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||
log.info("Current date {}", bussinesLocalDate);
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||
// Run Second time the Job
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
@@ -968,15 +964,11 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Delinquency Range is null {}", (firstTestCase == null));
|
||||
loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse);
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
bussinesLocalDate = Utils.getDateAsLocalDate("31 January 2012");
|
||||
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||
log.info("Current date {}", bussinesLocalDate);
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||
// Run Second time the Job
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
@@ -1059,15 +1051,11 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Product Arrears: {}", loanProductsProductIdResponseUpd.getInArrearsTolerance());
|
||||
assertEquals(0, loanProductsProductIdResponseUpd.getInArrearsTolerance());
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
bussinesLocalDate = Utils.getDateAsLocalDate("31 January 2012");
|
||||
LocalDate lastLoanCOBBusinessDate = bussinesLocalDate.minusDays(1);
|
||||
schedulerJobHelper.fastForwardTime(lastLoanCOBBusinessDate, bussinesLocalDate, jobName, responseSpec);
|
||||
log.info("Current date {}", bussinesLocalDate);
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||
// Run Second time the Job
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Get loan details expecting to have a delinquency classification
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
@@ -1114,24 +1102,22 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "04 February 2012");
|
||||
updateBusinessDate("06 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "07 February 2012");
|
||||
updateBusinessDate("09 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "10 March 2012");
|
||||
updateBusinessDate("12 March 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 2049.99, 36);
|
||||
});
|
||||
}
|
||||
@@ -1165,28 +1151,26 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "04 February 2012");
|
||||
updateBusinessDate("06 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "07 February 2012");
|
||||
updateBusinessDate("09 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
bussinesLocalDate = Utils.getDateAsLocalDate("10 February 2012");
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "10 March 2012");
|
||||
updateBusinessDate("12 March 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 2049.99, 36);
|
||||
});
|
||||
}
|
||||
@@ -1217,38 +1201,36 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
// delinquent days: 5
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "04 February 2012");
|
||||
updateBusinessDate("06 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
// Add delinquency pause on 06 February 2012
|
||||
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "07 February 2012");
|
||||
updateBusinessDate("09 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
// Add delinquency resume on 10 February 2012
|
||||
updateBusinessDate("10 February 2012");
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "11 February 2012");
|
||||
updateBusinessDate("13 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 8);
|
||||
|
||||
// Add new pause on 13 February 2012
|
||||
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "13 February 2012",
|
||||
"18 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "21 February 2012");
|
||||
updateBusinessDate("23 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 13);
|
||||
|
||||
// Add new pause on 23 February 2012
|
||||
@@ -1256,9 +1238,9 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
"28 February 2012");
|
||||
updateBusinessDate("25 February 2012");
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "25 February 2012");
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "10 March 2012");
|
||||
updateBusinessDate("12 March 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 2049.99, 29);
|
||||
});
|
||||
}
|
||||
@@ -1299,36 +1281,34 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
log.info("Loan Account Arrears {}", getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
assertEquals(3, getLoansLoanIdResponse.getInArrearsTolerance());
|
||||
|
||||
final String jobName = "Loan COB";
|
||||
|
||||
// delinquent days: 5
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "04 February 2012");
|
||||
updateBusinessDate("06 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
PostLoansDelinquencyActionResponse pauseDelinquencyResponse = loanTransactionHelper
|
||||
.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "06 February 2012", "10 March 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "07 February 2012");
|
||||
updateBusinessDate("09 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 5);
|
||||
|
||||
updateBusinessDate("10 February 2012");
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "10 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "11 February 2012");
|
||||
updateBusinessDate("13 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 8);
|
||||
|
||||
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "13 February 2012",
|
||||
"18 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "21 February 2012");
|
||||
updateBusinessDate("23 February 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
verifyDelinquency(loanId, "01 February 2012", 1033.33, 13);
|
||||
|
||||
pauseDelinquencyResponse = loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), PAUSE, "23 February 2012",
|
||||
@@ -1337,9 +1317,9 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
updateBusinessDate("25 February 2012");
|
||||
loanTransactionHelper.createLoanDelinquencyAction(loanId.longValue(), RESUME, "25 February 2012");
|
||||
|
||||
CobHelper.fastForwardLoansLastCOBDate(requestSpec, responseSpec204, loanId, "12 March 2012");
|
||||
updateBusinessDate("14 March 2012");
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
loanTransactionHelper.printDelinquencyData(getLoansLoanIdResponse);
|
||||
@@ -1447,10 +1427,10 @@ public class DelinquencyBucketsIntegrationTest extends BaseLoanIntegrationTest {
|
||||
getLoanProductsProductResponse.getId().toString(), operationDate, null);
|
||||
|
||||
// run cob for business date 01 January 2012
|
||||
final String jobName = "Loan COB";
|
||||
bussinesLocalDate = Utils.getDateAsLocalDate(operationDate);
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, bussinesLocalDate);
|
||||
schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
// Run the Loan inline COB Job
|
||||
inlineLoanCOBHelper.executeInlineCOB(Long.valueOf(loanId));
|
||||
|
||||
// Loan delinquency data
|
||||
GetLoansLoanIdResponse getLoansLoanIdResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId);
|
||||
|
||||
+2
@@ -192,6 +192,8 @@ public class UndoRepaymentWithDownPaymentIntegrationTest extends BaseLoanIntegra
|
||||
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||
assertEquals(500.0, Utils.getDoubleValue(loanDetails.getSummary().getTotalOutstanding()));
|
||||
globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE,
|
||||
new PutGlobalConfigurationsRequest().enabled(false));
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithPeriodicAccrualAccountingAndAdvancedPaymentAllocationStrategy() {
|
||||
|
||||
+1
-1
@@ -544,7 +544,7 @@ public class GlobalConfigurationHelper {
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("name",
|
||||
GlobalConfigurationConstants.ASSET_OWNER_TRANSFER_OUTSTANDING_INTEREST_CALCULATION_STRATEGY);
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("value", 0L);
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("enabled", false);
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("enabled", true);
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("trapDoor", false);
|
||||
assetOwnerTransferInterestOutstandingStrategy.put("string_value", "TOTAL_OUTSTANDING_INTEREST");
|
||||
defaults.add(assetOwnerTransferInterestOutstandingStrategy);
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ public class OfficeHelper {
|
||||
public static String getAsJSON(String externalId, final String openingDate) {
|
||||
final HashMap<String, String> map = new HashMap<>();
|
||||
map.put("parentId", "1");
|
||||
map.put("name", Utils.uniqueRandomStringGenerator("Office_", 4));
|
||||
map.put("name", Utils.uniqueRandomStringGenerator("O_", 9));
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("locale", "en");
|
||||
map.put("openingDate", openingDate);
|
||||
|
||||
+1
-1
@@ -272,7 +272,7 @@ public class SchedulerJobHelper {
|
||||
|
||||
private void awaitJob(Instant beforeExecuteTime, Supplier<Callable<Map<String, String>>> retrieveLastRunHistory) {
|
||||
final Duration timeout = Duration.ofMinutes(2);
|
||||
final Duration pause = Duration.ofSeconds(5);
|
||||
final Duration pause = Duration.ofSeconds(1);
|
||||
DateTimeFormatter df = DateTimeFormatter.ISO_INSTANT; // FINERACT-926
|
||||
// Await JobDetailData.lastRunHistory [JobDetailHistoryData]
|
||||
// jobRunStartTime >= beforeExecuteTime (or timeout)
|
||||
|
||||
+4
-2
@@ -109,6 +109,7 @@ public class SearchExternalAssetOwnerTransferTest extends ExternalAssetOwnerTran
|
||||
|
||||
@Test
|
||||
public void initialSearchExternalAssetOwnerTransferUsingTextTest() {
|
||||
saleActiveLoanToExternalAssetOwnerWithSearching();
|
||||
String textToSearch = UUID.randomUUID().toString();
|
||||
PagedRequestExternalAssetOwnerSearchRequest searchRequest = EXTERNAL_ASSET_OWNER_HELPER
|
||||
.buildExternalAssetOwnerSearchRequest(textToSearch, "", null, null, 0, 10);
|
||||
@@ -118,10 +119,10 @@ public class SearchExternalAssetOwnerTransferTest extends ExternalAssetOwnerTran
|
||||
|
||||
// Search over the current Asset Transfers and get just the first five
|
||||
textToSearch = "";
|
||||
searchRequest = EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch, "", null, null, 0, 5);
|
||||
searchRequest = EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch, "", null, null, 0, 1);
|
||||
response = EXTERNAL_ASSET_OWNER_HELPER.searchExternalAssetOwnerTransfer(searchRequest);
|
||||
assertNotNull(response);
|
||||
assertEquals(5, response.getContent().size(), "Expecting first five results");
|
||||
assertEquals(1, response.getContent().size(), "Expecting first result");
|
||||
|
||||
textToSearch = response.getContent().iterator().next().getOwner().getExternalId();
|
||||
searchRequest = EXTERNAL_ASSET_OWNER_HELPER.buildExternalAssetOwnerSearchRequest(textToSearch, "", null, null, 0, 5);
|
||||
@@ -133,6 +134,7 @@ public class SearchExternalAssetOwnerTransferTest extends ExternalAssetOwnerTran
|
||||
|
||||
@Test
|
||||
public void initialSearchExternalAssetOwnerTransferUsingEffectiveDateTest() {
|
||||
saleActiveLoanToExternalAssetOwnerWithSearching();
|
||||
final String attribute = "effective";
|
||||
LocalDate fromDate = Utils.getDateAsLocalDate("01 March 2023");
|
||||
LocalDate toDate = fromDate.plusMonths(3);
|
||||
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on any error
|
||||
set -e
|
||||
|
||||
# Get the number of shards (default to 10 if not provided)
|
||||
NUM_SHARDS=${1:-10}
|
||||
# Convert to 0-based index for internal calculations
|
||||
SHARD_INDEX_ZERO_BASED=$((${2:-1} - 1))
|
||||
SHARD_INDEX=${2:-1} # Keep original 1-based index for output
|
||||
|
||||
# Directory containing feature files
|
||||
FEATURES_DIR="fineract-e2e-tests-runner/src/test/resources/features"
|
||||
TEMP_FILE="/tmp/feature_scenarios_$(date +%s).txt"
|
||||
|
||||
# Check if features directory exists
|
||||
if [ ! -d "$FEATURES_DIR" ]; then
|
||||
echo "Error: Features directory not found at $FEATURES_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to count scenarios in a feature file
|
||||
count_scenarios() {
|
||||
local file="$1"
|
||||
# Count scenario and scenario outline keywords, excluding commented lines
|
||||
grep -v '^[[:space:]]*#' "$file" | grep -c 'Scenario\( Outline\)\?:' || echo "0"
|
||||
}
|
||||
|
||||
# Process each feature file and count scenarios
|
||||
echo "Analyzing feature files to count scenarios..."
|
||||
> "$TEMP_FILE"
|
||||
|
||||
while IFS= read -r -d $'\0' file; do
|
||||
# Remove the 'fineract-e2e-tests-runner/' prefix
|
||||
rel_path="${file#fineract-e2e-tests-runner/}"
|
||||
scenario_count=$(count_scenarios "$file")
|
||||
echo "$scenario_count $rel_path"
|
||||
done < <(find "$FEATURES_DIR" -type f -name '*.feature' -print0) | sort -nr > "$TEMP_FILE"
|
||||
|
||||
# Read the sorted list of features
|
||||
SORTED_FEATURES=()
|
||||
while IFS= read -r line; do
|
||||
# Extract just the file path (removing the scenario count)
|
||||
path=$(echo "$line" | awk '{$1=""; print $0}' | sed 's/^ //')
|
||||
[ -n "$path" ] && SORTED_FEATURES+=("$path")
|
||||
done < "$TEMP_FILE"
|
||||
TOTAL_FEATURES=${#SORTED_FEATURES[@]}
|
||||
|
||||
# Check if any feature files were found
|
||||
if [ $TOTAL_FEATURES -eq 0 ]; then
|
||||
echo "Warning: No feature files found in $FEATURES_DIR"
|
||||
# Create an empty feature list file
|
||||
FEATURE_LIST_FILE="feature_shard_${SHARD_INDEX}.txt"
|
||||
> "$FEATURE_LIST_FILE"
|
||||
echo "Created empty feature list file: $FEATURE_LIST_FILE"
|
||||
rm -f "$TEMP_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create a file to store the feature file paths
|
||||
# Use the 1-based index for the filename
|
||||
FEATURE_LIST_FILE="feature_shard_${SHARD_INDEX}.txt"
|
||||
> "$FEATURE_LIST_FILE"
|
||||
|
||||
# Distribute features to shards in a round-robin fashion to balance scenario counts
|
||||
for ((i=0; i<TOTAL_FEATURES; i++)); do
|
||||
if (( i % NUM_SHARDS == SHARD_INDEX_ZERO_BASED )); then
|
||||
echo "${SORTED_FEATURES[$i]}" >> "$FEATURE_LIST_FILE"
|
||||
fi
|
||||
done
|
||||
|
||||
# Count scenarios in this shard
|
||||
SHARD_SCENARIOS=0
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
count=$(grep -m 1 -F "$line" "$TEMP_FILE" | awk '{print $1}')
|
||||
SHARD_SCENARIOS=$((SHARD_SCENARIOS + count))
|
||||
done < "$FEATURE_LIST_FILE"
|
||||
|
||||
# Get the list of features in this shard for output
|
||||
SHARD_FEATURES=()
|
||||
while IFS= read -r line; do
|
||||
[ -n "$line" ] && SHARD_FEATURES+=("$line")
|
||||
done < "$FEATURE_LIST_FILE"
|
||||
NUM_FEATURES=${#SHARD_FEATURES[@]}
|
||||
|
||||
# Output the shard information
|
||||
echo "Shard $SHARD_INDEX (1-based): $NUM_FEATURES features with $SHARD_SCENARIOS total scenarios"
|
||||
if [ $NUM_FEATURES -gt 0 ]; then
|
||||
echo "First feature: ${SHARD_FEATURES[0]}"
|
||||
if [ $NUM_FEATURES -gt 1 ]; then
|
||||
echo "Last feature: ${SHARD_FEATURES[$((NUM_FEATURES-1))]}"
|
||||
fi
|
||||
echo "Features in this shard (scenario count):"
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
count=$(grep -m 1 -F "$line" "$TEMP_FILE" | awk '{print $1}')
|
||||
echo " - $line ($count scenarios)"
|
||||
done < "$FEATURE_LIST_FILE"
|
||||
fi
|
||||
|
||||
echo "Feature list written to $FEATURE_LIST_FILE"
|
||||
|
||||
# Clean up temp file
|
||||
rm -f "$TEMP_FILE"
|
||||
|
||||
# Set output for GitHub Actions
|
||||
if [ -n "$GITHUB_OUTPUT" ]; then
|
||||
echo "FEATURE_LIST_FILE=$FEATURE_LIST_FILE" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# Usage: ./split-tests.sh <total-shards> <shard-index>
|
||||
set -e
|
||||
|
||||
TOTAL_SHARDS=$1
|
||||
SHARD_INDEX=$2
|
||||
|
||||
if [[ -z "$TOTAL_SHARDS" || -z "$SHARD_INDEX" ]]; then
|
||||
echo "ERROR: You must provide <total-shards> and <shard-index>."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔍 Searching for eligible JUnit test classes..."
|
||||
|
||||
ALL_TESTS=$(find . -type f -path "*/src/test/java/*Test.java" \
|
||||
| while read filepath; do
|
||||
filename=$(basename "$filepath")
|
||||
|
||||
# Skip abstract class or interface by name
|
||||
if [[ "$filename" =~ ^Abstract.*Test\.java$ || "$filename" =~ .*AbstractTest\.java$ ]]; then
|
||||
echo "Skipping abstract-named file: $filename" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip if file doesn't contain valid JUnit annotations
|
||||
if ! grep -qE "@Test|@Nested|@ParameterizedTest" "$filepath"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract module directory path (everything before /src/test/java)
|
||||
module_path="${filepath%%/src/test/java/*}"
|
||||
# Convert from ./custom/acme/loan/job to :custom:acme:loan:job
|
||||
module_name=$(echo "$module_path" | sed 's|^\./||; s|/|:|g; s|^|:|')
|
||||
|
||||
# Extract fully qualified test class name
|
||||
class_name=$(echo "$filepath" | sed 's|^.*src/test/java/||; s|/|.|g; s|.java$||')
|
||||
|
||||
echo "$module_name,$class_name"
|
||||
done \
|
||||
| sort)
|
||||
|
||||
TOTAL_COUNT=$(echo "$ALL_TESTS" | wc -l)
|
||||
echo "Found $TOTAL_COUNT eligible test classes."
|
||||
|
||||
SELECTED_CLASSES=$(echo "$ALL_TESTS" \
|
||||
| awk -v ts="$TOTAL_SHARDS" -v si="$SHARD_INDEX" 'NR % ts == (si - 1)')
|
||||
|
||||
OUTPUT_FILE="shard-tests_${SHARD_INDEX}.txt"
|
||||
echo "$SELECTED_CLASSES" > "$OUTPUT_FILE"
|
||||
|
||||
echo "Selected $(wc -l < "$OUTPUT_FILE") classes for shard $SHARD_INDEX of $TOTAL_SHARDS:"
|
||||
cat "$OUTPUT_FILE"
|
||||
Reference in New Issue
Block a user