Add samples/usecase/usecase1 UI smoke test and align doc/sample artifacts
#596
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # The contents of this file are subject to the terms of the Common Development and | |
| # Distribution License (the License). You may not use this file except in compliance with the | |
| # License. | |
| # | |
| # You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the | |
| # specific language governing permission and limitations under the License. | |
| # | |
| # When distributing Covered Software, include this CDDL Header Notice in each file and include | |
| # the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL | |
| # Header, with the fields enclosed by brackets [] replaced by your own identifying | |
| # information: "Portions copyright [year] [name of copyright owner]". | |
| # | |
| # Copyright 2024-2026 3A Systems, LLC. | |
| name: Build | |
| on: | |
| push: | |
| branches: [ 'sustaining/6.3.x','master', 'issues/**', 'features/**' ] | |
| pull_request: | |
| jobs: | |
| build-maven: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| java: [ '17', '21', '25', '26' ] | |
| os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ] | |
| fail-fast: false | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| submodules: recursive | |
| - name: Java ${{ matrix.Java }} (${{ matrix.os }}) | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: ${{ matrix.java }} | |
| distribution: 'zulu' | |
| - name: Cache Maven packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.m2/repository | |
| key: ${{ runner.os }}-m2-repository-${{ hashFiles('**/pom.xml') }} | |
| restore-keys: ${{ runner.os }}-m2-repository | |
| - name: Build with Maven | |
| env: | |
| MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10 | |
| run: mvn --batch-mode --errors --update-snapshots verify --file pom.xml | |
| - name: Test on Unix | |
| if: runner.os != 'Windows' | |
| run: | | |
| if [ "$RUNNER_OS" == "macOS" ]; then | |
| brew install coreutils | |
| fi | |
| unzip openidm-zip/target/openidm-*.zip | |
| openidm/startup.sh & | |
| timeout 3m bash -c 'until grep -q "OpenIDM ready" openidm/logs/openidm0.log.0 ; do sleep 5; done' || cat openidm/logs/openidm0.log.0 | |
| grep -q "OpenIDM ready" openidm/logs/openidm0.log.0 | |
| ! grep -E "ERROR|SEVERE|Exception|Throwable" openidm/logs/openidm0.log.0 | |
| - name: Test on Windows | |
| if: runner.os == 'Windows' | |
| run: | | |
| unzip openidm-zip/target/openidm-*.zip | |
| cd openidm | |
| cmd /c "START /b startup.bat" | |
| Start-Sleep -s 180 | |
| type logs\openidm0.log.0 | |
| findstr "OpenIDM ready" logs\openidm0.log.0 | |
| if (Select-String -Path logs\openidm0.log.0 -Pattern 'ERROR|SEVERE|Exception|Throwable' -CaseSensitive -Quiet) { | |
| Write-Host "Errors or exceptions detected in openidm0.log.0" | |
| Select-String -Path logs\openidm0.log.0 -Pattern 'ERROR|SEVERE|Exception|Throwable' -CaseSensitive | |
| exit 1 | |
| } | |
| - name: Upload failure artifacts | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ failure() }} | |
| with: | |
| name: failure-${{ matrix.os }}-${{ matrix.java }} | |
| retention-days: 1 | |
| path: | | |
| ** | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.os }}-${{ matrix.java }} | |
| retention-days: 5 | |
| path: | | |
| openidm-zip/target/*.zip | |
| ui-smoke-tests: | |
| runs-on: ubuntu-latest | |
| needs: build-maven | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| java: [ '17', '26' ] | |
| context_path: [ "", "/myidm" ] | |
| samples: [ "", "samples/getting-started", "samples/workflow", "samples/usecase/usecase1" ] | |
| include: | |
| - context_path: "" | |
| context_label: default | |
| - context_path: "/myidm" | |
| context_label: myidm | |
| - samples: "" | |
| samples_label: default | |
| - samples: "samples/getting-started" | |
| samples_label: getting-started | |
| - samples: "samples/workflow" | |
| samples_label: workflow | |
| - samples: "samples/usecase/usecase1" | |
| samples_label: usecase1 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Java ${{ matrix.java }} | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: ${{ matrix.java }} | |
| distribution: 'zulu' | |
| - name: Download OpenIDM zip artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: ubuntu-latest-${{ matrix.java }} | |
| path: openidm-zip/target | |
| - name: Unpack OpenIDM | |
| run: unzip -q openidm-zip/target/openidm-*.zip | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: ${{ runner.os }}-playwright-browsers | |
| restore-keys: ${{ runner.os }}-playwright- | |
| - name: Start OpenDJ for usecase samples | |
| if: startsWith(matrix.samples, 'samples/usecase') | |
| run: | | |
| # samples/usecase/usecase1..7 all assume an LDAP server bound to | |
| # cn=Directory Manager / password on port 1389 with the contents | |
| # of samples/usecase/data/hr_data.ldif imported. Provision it via | |
| # the openidentityplatform/opendj image so the smoke test does not | |
| # require a manually-installed directory server. | |
| mkdir -p /tmp/opendj-bootstrap | |
| # The openidm zip assembly does not currently package | |
| # samples/usecase/data/, so source the LDIF directly from the | |
| # checkout instead of the unpacked deployment. | |
| cp openidm-zip/src/main/resources/samples/usecase/data/hr_data.ldif /tmp/opendj-bootstrap/ | |
| docker run -d --name opendj \ | |
| -p 1389:1389 -p 1636:1636 -p 4444:4444 \ | |
| -e BASE_DN=dc=example,dc=com \ | |
| -e ROOT_USER_DN="cn=Directory Manager" \ | |
| -e ROOT_PASSWORD=password \ | |
| -e ADD_BASE_ENTRY= \ | |
| -v /tmp/opendj-bootstrap:/opt/opendj/bootstrap/data \ | |
| openidentityplatform/opendj:latest | |
| # Wait for OpenDJ to report readiness in its container logs. | |
| for i in $(seq 1 60); do | |
| if docker logs opendj 2>&1 | grep -q "OpenDJ is started"; then | |
| echo "OpenDJ is started" | |
| break | |
| fi | |
| sleep 2 | |
| done | |
| docker logs opendj 2>&1 | grep -q "OpenDJ is started" || { | |
| echo "OpenDJ did not start"; docker logs opendj; exit 1; | |
| } | |
| - name: Start OpenIDM (context_path='${{ matrix.context_path }}', samples='${{ matrix.samples }}') | |
| run: | | |
| OPTS="" | |
| if [ -n "${{ matrix.context_path }}" ]; then | |
| OPTS="-Dopenidm.context.path=${{ matrix.context_path }}" | |
| fi | |
| ARGS="" | |
| if [ -n "${{ matrix.samples }}" ]; then | |
| ARGS="-p ${{ matrix.samples }}" | |
| fi | |
| OPENIDM_OPTS="$OPTS" openidm/startup.sh $ARGS & | |
| timeout 3m bash -c 'until grep -q "OpenIDM ready" openidm/logs/openidm0.log.0 ; do sleep 5; done' || cat openidm/logs/openidm0.log.0 | |
| grep -q "OpenIDM ready" openidm/logs/openidm0.log.0 | |
| # Allow-list of documented, expected log-noise per sample. The | |
| # usecase1 walk-through explicitly relies on three iterative recon | |
| # passes: each early pass legitimately fails for source rows whose | |
| # 'manager' attribute references a managed/user that has not yet | |
| # been created, producing the SynchronizationException / | |
| # BadRequestException / NotFoundException stack traces logged | |
| # below. They are part of the documented behaviour and must not | |
| # turn the smoke-test job red. All other ERROR / SEVERE / | |
| # Exception / Throwable lines remain failing. | |
| ALLOW="" | |
| case "${{ matrix.samples }}" in | |
| samples/usecase/usecase1) | |
| ALLOW="The referenced relationship 'managed/user/[^']+', does not exist|Object [^ ]+ not found in managed/user|org\\.forgerock\\.openidm\\.sync\\.SynchronizationException: The referenced relationship" | |
| ;; | |
| esac | |
| if [ -n "$ALLOW" ]; then | |
| ! grep -E "ERROR|SEVERE|Exception|Throwable" openidm/logs/openidm0.log.0 \ | |
| | grep -vE "$ALLOW" \ | |
| | grep -E "ERROR|SEVERE|Exception|Throwable" -q | |
| else | |
| ! grep -E "ERROR|SEVERE|Exception|Throwable" openidm/logs/openidm0.log.0 | |
| fi | |
| - name: UI Smoke Tests (Playwright) | |
| run: | | |
| cd e2e | |
| npm init -y | |
| npm install @playwright/test | |
| npx playwright install chromium --with-deps | |
| npx playwright test --reporter=list | |
| env: | |
| OPENIDM_URL: http://localhost:8080 | |
| OPENIDM_CONTEXT_PATH: ${{ matrix.context_path }} | |
| OPENIDM_SAMPLE: ${{ matrix.samples }} | |
| - name: Upload failure artifacts | |
| uses: actions/upload-artifact@v7 | |
| if: ${{ failure() }} | |
| with: | |
| name: failure-ui-java${{ matrix.java }}-${{ matrix.context_label }}-${{ matrix.samples_label }} | |
| retention-days: 1 | |
| path: | | |
| openidm/logs/** | |
| e2e/playwright-report/** | |
| e2e/test-results/** | |
| - name: Print OpenDJ logs | |
| if: ${{ always() && startsWith(matrix.samples, 'samples/usecase') }} | |
| run: docker logs opendj || true | |
| - name: Print openidm logs | |
| if: ${{ always() }} | |
| shell: bash | |
| run: | | |
| if [ -d openidm/logs ]; then | |
| find openidm/logs -type f -printf '%T@ %p\n' | sort -n | cut -d' ' -f2- | while read -r f; do | |
| echo "===== $f =====" | |
| cat "$f" | |
| done | |
| else | |
| echo "openidm/logs directory not found" | |
| exit 0 | |
| fi | |
| echo "----- Checking logs for errors/exceptions -----" | |
| # Per-sample allow-list of expected, documented log-noise. See the | |
| # rationale in the "Start OpenIDM" step above. Any pattern listed | |
| # here is filtered out before deciding whether errors remain. | |
| ALLOW="" | |
| case "${{ matrix.samples }}" in | |
| samples/usecase/usecase1) | |
| ALLOW="The referenced relationship 'managed/user/[^']+', does not exist|Object [^ ]+ not found in managed/user|org\\.forgerock\\.openidm\\.sync\\.SynchronizationException: The referenced relationship" | |
| ;; | |
| esac | |
| status=0 | |
| while IFS= read -r f; do | |
| if [ -n "$ALLOW" ]; then | |
| grep -E -n "ERROR|SEVERE|Exception|Throwable" "$f" 2>/dev/null \ | |
| | grep -vE "$ALLOW" > /tmp/log_errors.$$ || true | |
| [ -s /tmp/log_errors.$$ ] && hit=0 || hit=1 | |
| else | |
| if grep -E -n "ERROR|SEVERE|Exception|Throwable" "$f" > /tmp/log_errors.$$ 2>/dev/null; then | |
| hit=0 | |
| else | |
| hit=1 | |
| fi | |
| fi | |
| if [ "$hit" -eq 0 ]; then | |
| echo "Found errors/exceptions in $f:" | |
| cat /tmp/log_errors.$$ | |
| status=1 | |
| fi | |
| rm -f /tmp/log_errors.$$ | |
| done < <(find openidm/logs -type f) | |
| if [ "$status" -ne 0 ]; then | |
| echo "Errors or exceptions detected in openidm logs" | |
| exit 1 | |
| fi | |
| echo "No errors or exceptions detected in openidm logs" | |
| build-docker: | |
| runs-on: 'ubuntu-latest' | |
| services: | |
| registry: | |
| image: registry:2 | |
| ports: | |
| - 5000:5000 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get latest release version | |
| shell: bash | |
| run: | | |
| export git_version_last="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenIDM/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)" ; echo "last release: $git_version_last" | |
| echo "release_version=$git_version_last" >> $GITHUB_ENV | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: | | |
| localhost:5000/${{ github.repository }} | |
| tags: | | |
| type=raw,value=${{ env.release_version }} | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| driver-opts: network=host | |
| - name: Build image (default) | |
| uses: docker/build-push-action@v7 | |
| continue-on-error: true | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| build-args: | | |
| VERSION=${{ env.release_version }} | |
| platforms: linux/amd64, linux/arm64/8, linux/ppc64le, linux/s390x #, linux/arm/v7 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| - name: Docker test | |
| shell: bash | |
| run: | | |
| docker run --rm -it -d --memory="1g" --name=test localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }} | |
| timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test | grep -q \"healthy\"; do sleep 10; done' | |
| build-docker-alpine: | |
| runs-on: 'ubuntu-latest' | |
| services: | |
| registry: | |
| image: registry:2 | |
| ports: | |
| - 5000:5000 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get latest release version | |
| shell: bash | |
| run: | | |
| export git_version_last="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenIDM/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)" ; echo "last release: $git_version_last" | |
| echo "release_version=$git_version_last" >> $GITHUB_ENV | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: | | |
| localhost:5000/${{ github.repository }} | |
| tags: | | |
| type=raw,value=alpine | |
| type=raw,value=${{ env.release_version }}-alpine | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| driver-opts: network=host | |
| - name: Build image | |
| continue-on-error: true | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: ./Dockerfile-alpine | |
| build-args: | | |
| VERSION=${{ env.release_version }} | |
| platforms: linux/amd64, linux/arm64/8, linux/s390x, linux/ppc64le | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| - name: Docker test | |
| shell: bash | |
| run: | | |
| docker run --rm -it -d --memory="1g" --name=test localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}-alpine | |
| timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test | grep -q \"healthy\"; do sleep 10; done' |