From 80a41b0cbc10b002a8dfe44de0046c18aa40317b Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Mon, 30 Mar 2026 20:30:49 +0200 Subject: [PATCH 01/10] feat: [OCISDEV-744] e2e-test --- .github/workflows/acceptance-tests.yml | 563 +++++++++++++++---------- tests/acceptance/run-e2e.py | 256 +++++++++++ tests/acceptance/run-e2e.sh | 65 +++ 3 files changed, 657 insertions(+), 227 deletions(-) create mode 100755 tests/acceptance/run-e2e.py create mode 100755 tests/acceptance/run-e2e.sh diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index fcd7fcfe1fd..bed32a33976 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -5,259 +5,368 @@ on: workflow_dispatch: jobs: - coding-standard: - name: coding-standard - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 - with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer - - name: PHP code style - run: | - make vendor-bin-codestyle - make vendor-bin-codesniffer - make test-php-style - - name: Check env var annotations - run: make check-env-var-annotations - - check-gherkin-standard: - name: check-gherkin-standard - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "24" - - name: Lint feature files - run: | - npm install -g @gherlint/gherlint@1.1.0 - make test-gherkin-lint - - check-suites-in-expected-failures: - name: check-suites-in-expected-failures - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Check suites - run: bash tests/acceptance/check-deleted-suites-in-expected-failure.sh - - build-and-test: - name: build-and-test - needs: [coding-standard, check-gherkin-standard, check-suites-in-expected-failures] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 - with: - go-version-file: go.mod - cache: true - - - name: Build ocis - run: make -C ocis build - - - name: Unit tests - run: make test - - local-api-tests: - name: ${{ matrix.suite }} - needs: [build-and-test] - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - suite: - # contract & locks - - apiContract - - apiLocks - # settings & notifications (needs email) - - apiSettings - - apiNotification - - apiCors - # graph - - apiGraphUser - - apiGraph - - apiGraphGroup - # spaces & dav - - apiSpaces - - apiSpacesShares - - apiSpacesDavOperation - - apiDownloads - - apiAsyncUpload - - apiDepthInfinity - - apiArchiver - - apiActivities - # search - - apiSearch1 - # - apiSearch2 - - apiSearchContent # needs Tika - # sharing - - apiSharingNgShares - - apiReshare - - apiSharingNgPermissions - - apiSharingNgAdditionalShareRole - - apiSharingNgDriveInvitation - - apiSharingNgItemInvitation - - apiSharingNgDriveLinkShare - - apiSharingNgItemLinkShare - - apiSharingNgLinkShareManagement - # auth - - apiAuthApp - # antivirus (needs ClamAV) - - apiAntivirus - # federation (needs email + federation ocis) - # - apiOcm - # collaboration (needs WOPI) - - apiCollaboration - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 - with: - go-version-file: go.mod - cache: true - - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "24" - - - name: Enable pnpm - run: corepack enable && corepack prepare pnpm@10.28.1 --activate - - - name: Install libcurl 8.12.0 from source - run: | - sudo apt-get update -qq - sudo apt-get install -y libssl-dev libnghttp2-dev libpsl-dev libldap-dev libssh-dev zlib1g-dev libvips-dev - cd /tmp - curl -sLO https://curl.se/download/curl-8.12.0.tar.gz - tar xzf curl-8.12.0.tar.gz - cd curl-8.12.0 - ./configure --with-ssl --with-zlib --with-nghttp2 --prefix=/usr/local --enable-versioned-symbols --silent - make -j$(nproc) --silent - sudo make install --silent - sudo ldconfig - curl --version | head -1 - php -r ' - $v = curl_version()["version"]; - echo "PHP curl: $v\n"; - if (version_compare($v, "8.12.0", "<")) { - fwrite(STDERR, "FATAL: PHP sees libcurl $v, need >= 8.12.0\n"); - exit(1); - } - ' - - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 - with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer +# coding-standard: +# name: coding-standard +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 +# with: +# php-version: "8.4" +# extensions: curl, xml, mbstring, zip +# tools: composer +# - name: PHP code style +# run: | +# make vendor-bin-codestyle +# make vendor-bin-codesniffer +# make test-php-style +# - name: Check env var annotations +# run: make check-env-var-annotations +# +# check-gherkin-standard: +# name: check-gherkin-standard +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 +# with: +# node-version: "24" +# - name: Lint feature files +# run: | +# npm install -g @gherlint/gherlint@1.1.0 +# make test-gherkin-lint +# +# check-suites-in-expected-failures: +# name: check-suites-in-expected-failures +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - name: Check suites +# run: bash tests/acceptance/check-deleted-suites-in-expected-failure.sh +# +# build-and-test: +# name: build-and-test +# needs: [coding-standard, check-gherkin-standard, check-suites-in-expected-failures] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 +# with: +# go-version-file: go.mod +# cache: true +# +# - name: Build ocis +# run: make -C ocis build +# +# - name: Unit tests +# run: make test +# +# local-api-tests: +# name: ${{ matrix.suite }} +# needs: [build-and-test] +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# suite: +# # contract & locks +# - apiContract +# - apiLocks +# # settings & notifications (needs email) +# - apiSettings +# - apiNotification +# - apiCors +# # graph +# - apiGraphUser +# - apiGraph +# - apiGraphGroup +# # spaces & dav +# - apiSpaces +# - apiSpacesShares +# - apiSpacesDavOperation +# - apiDownloads +# - apiAsyncUpload +# - apiDepthInfinity +# - apiArchiver +# - apiActivities +# # search +# - apiSearch1 +# # - apiSearch2 +# - apiSearchContent # needs Tika +# # sharing +# - apiSharingNgShares +# - apiReshare +# - apiSharingNgPermissions +# - apiSharingNgAdditionalShareRole +# - apiSharingNgDriveInvitation +# - apiSharingNgItemInvitation +# - apiSharingNgDriveLinkShare +# - apiSharingNgItemLinkShare +# - apiSharingNgLinkShareManagement +# # auth +# - apiAuthApp +# # antivirus (needs ClamAV) +# - apiAntivirus +# # federation (needs email + federation ocis) +# # - apiOcm +# # collaboration (needs WOPI) +# # - apiCollaboration +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 +# with: +# go-version-file: go.mod +# cache: true +# +# - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 +# with: +# node-version: "24" +# +# - name: Enable pnpm +# run: corepack enable && corepack prepare pnpm@10.28.1 --activate +# +# - name: Install libcurl 8.12.0 from source +# run: | +# sudo apt-get update -qq +# sudo apt-get install -y libssl-dev libnghttp2-dev libpsl-dev libldap-dev libssh-dev zlib1g-dev libvips-dev +# cd /tmp +# curl -sLO https://curl.se/download/curl-8.12.0.tar.gz +# tar xzf curl-8.12.0.tar.gz +# cd curl-8.12.0 +# ./configure --with-ssl --with-zlib --with-nghttp2 --prefix=/usr/local --enable-versioned-symbols --silent +# make -j$(nproc) --silent +# sudo make install --silent +# sudo ldconfig +# curl --version | head -1 +# php -r ' +# $v = curl_version()["version"]; +# echo "PHP curl: $v\n"; +# if (version_compare($v, "8.12.0", "<")) { +# fwrite(STDERR, "FATAL: PHP sees libcurl $v, need >= 8.12.0\n"); +# exit(1); +# } +# ' +# +# - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 +# with: +# php-version: "8.4" +# extensions: curl, xml, mbstring, zip +# tools: composer +# +# - name: Run ${{ matrix.suite }} +# run: BEHAT_SUITES=${{ matrix.suite }} python3 tests/acceptance/run-github.py +# +# cli-tests: +# needs: [build-and-test] +# name: ${{ matrix.suite }} +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# suite: +# - cliCommands,apiServiceAvailability # grouped like drone; needs ClamAV + email +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 +# with: +# go-version-file: go.mod +# cache: true +# +# - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 +# with: +# node-version: "24" +# +# - name: Enable pnpm +# run: corepack enable && corepack prepare pnpm@10.28.1 --activate +# +# - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 +# with: +# php-version: "8.4" +# extensions: curl, xml, mbstring, zip +# tools: composer +# +# - name: Run ${{ matrix.suite }} +# run: BEHAT_SUITES="${{ matrix.suite }}" python3 tests/acceptance/run-github.py +# +# core-api-tests: +# name: ${{ matrix.suite }} +# needs: [build-and-test] +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# suite: +# - "coreApiShareManagementBasicToShares,coreApiShareManagementToShares" +# - "coreApiSharees,coreApiSharePublicLink2" +# - "coreApiShareOperationsToShares1,coreApiShareOperationsToShares2,coreApiSharePublicLink1,coreApiShareCreateSpecialToShares1,coreApiShareCreateSpecialToShares2,coreApiShareUpdateToShares" +# - "coreApiTrashbin,coreApiTrashbinRestore,coreApiWebdavEtagPropagation1,coreApiWebdavEtagPropagation2" +# steps: +# - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 +# - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 +# with: +# go-version-file: go.mod +# cache: true +# +# - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 +# with: +# node-version: "24" +# +# - name: Enable pnpm +# run: corepack enable && corepack prepare pnpm@10.28.1 --activate +# +# - name: Install libcurl 8.12.0 from source +# run: | +# sudo apt-get update -qq +# sudo apt-get install -y libssl-dev libnghttp2-dev libpsl-dev libldap-dev libssh-dev zlib1g-dev libvips-dev +# cd /tmp +# curl -sLO https://curl.se/download/curl-8.12.0.tar.gz +# tar xzf curl-8.12.0.tar.gz +# cd curl-8.12.0 +# ./configure --with-ssl --with-zlib --with-nghttp2 --prefix=/usr/local --enable-versioned-symbols --silent +# make -j$(nproc) --silent +# sudo make install --silent +# sudo ldconfig +# curl --version | head -1 +# php -r ' +# $v = curl_version()["version"]; +# echo "PHP curl: $v\n"; +# if (version_compare($v, "8.12.0", "<")) { +# fwrite(STDERR, "FATAL: PHP sees libcurl $v, need >= 8.12.0\n"); +# exit(1); +# } +# ' +# +# - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 +# with: +# php-version: "8.4" +# extensions: curl, xml, mbstring, zip +# tools: composer +# +# - name: Run ${{ matrix.suite }} +# run: > +# BEHAT_SUITES="${{ matrix.suite }}" +# ACCEPTANCE_TEST_TYPE=core-api +# EXPECTED_FAILURES_FILE=tests/acceptance/expected-failures-API-on-OCIS-storage.md +# python3 tests/acceptance/run-github.py +# +# - name: Upload test logs +# if: failure() +# uses: actions/upload-artifact@v4 +# with: +# name: test-logs-${{ matrix.suite }} +# path: tests/acceptance/output/ - - name: Run ${{ matrix.suite }} - run: BEHAT_SUITES=${{ matrix.suite }} python3 tests/acceptance/run-github.py - cli-tests: - needs: [build-and-test] - name: ${{ matrix.suite }} + e2e-tests: + name: e2e-${{ matrix.suite }} + needs: [] runs-on: ubuntu-latest strategy: fail-fast: false matrix: - suite: - - cliCommands,apiServiceAvailability # grouped like drone; needs ClamAV + email + include: + - suite: part-1 + args: "--total-parts 4 --xsuites search,app-provider,ocm,keycloak --run-part 1" + - suite: part-2 + args: "--total-parts 4 --xsuites search,app-provider,ocm,keycloak --run-part 2" + - suite: part-3 + args: "--total-parts 4 --xsuites search,app-provider,ocm,keycloak --run-part 3" + - suite: part-4 + args: "--total-parts 4 --xsuites search,app-provider,ocm,keycloak --run-part 4" + - suite: search + args: "--suites search" + tika: true + - suite: keycloak + args: "--suites journeys,keycloak" + keycloak: true steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: go.mod cache: true - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 with: node-version: "24" - - - name: Enable pnpm - run: corepack enable && corepack prepare pnpm@10.28.1 --activate - - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 + - name: Setup pnpm + uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer - - - name: Run ${{ matrix.suite }} - run: BEHAT_SUITES="${{ matrix.suite }}" python3 tests/acceptance/run-github.py - - core-api-tests: - name: ${{ matrix.suite }} - needs: [build-and-test] - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - suite: - - "coreApiShareManagementBasicToShares,coreApiShareManagementToShares" - - "coreApiSharees,coreApiSharePublicLink2" - - "coreApiShareOperationsToShares1,coreApiShareOperationsToShares2,coreApiSharePublicLink1,coreApiShareCreateSpecialToShares1,coreApiShareCreateSpecialToShares2,coreApiShareUpdateToShares" - - "coreApiTrashbin,coreApiTrashbinRestore,coreApiWebdavEtagPropagation1,coreApiWebdavEtagPropagation2" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 - with: - go-version-file: go.mod - cache: true + version: "10.28.1" + - name: Generate code + run: | + pnpm config set store-dir ./.pnpm-store + make ci-node-generate + env: + CHROMEDRIVER_SKIP_DOWNLOAD: "true" - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + - name: Cache Playwright Chromium + uses: actions/cache@v4 with: - node-version: "24" + path: ~/.cache/ms-playwright + key: playwright-chromium-${{ hashFiles('.drone.env') }} - - name: Enable pnpm - run: corepack enable && corepack prepare pnpm@10.28.1 --activate + # --- Tika (search suite only) --- + - name: Start Tika + if: matrix.tika == true + run: | + docker run -d --name tika --network host apache/tika:3.2.2.0-full + timeout 120 bash -c 'until curl -sf http://localhost:9998; do sleep 2; done' + echo "tika ready." - - name: Install libcurl 8.12.0 from source + # --- Keycloak (keycloak suite only) --- + - name: Generate Keycloak certs + if: matrix.keycloak == true run: | - sudo apt-get update -qq - sudo apt-get install -y libssl-dev libnghttp2-dev libpsl-dev libldap-dev libssh-dev zlib1g-dev libvips-dev - cd /tmp - curl -sLO https://curl.se/download/curl-8.12.0.tar.gz - tar xzf curl-8.12.0.tar.gz - cd curl-8.12.0 - ./configure --with-ssl --with-zlib --with-nghttp2 --prefix=/usr/local --enable-versioned-symbols --silent - make -j$(nproc) --silent - sudo make install --silent - sudo ldconfig - curl --version | head -1 - php -r ' - $v = curl_version()["version"]; - echo "PHP curl: $v\n"; - if (version_compare($v, "8.12.0", "<")) { - fwrite(STDERR, "FATAL: PHP sees libcurl $v, need >= 8.12.0\n"); - exit(1); - } - ' + mkdir -p keycloak-certs + openssl req -x509 -newkey rsa:2048 \ + -keyout keycloak-certs/keycloakkey.pem \ + -out keycloak-certs/keycloakcrt.pem \ + -nodes -days 365 -subj '/CN=keycloak' + chmod -R 777 keycloak-certs - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 - with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer + - name: Start Postgres + if: matrix.keycloak == true + run: | + docker run -d --name postgres --network host \ + -e POSTGRES_DB=keycloak \ + -e POSTGRES_USER=keycloak \ + -e POSTGRES_PASSWORD=keycloak \ + postgres:alpine3.18 + timeout 30 bash -c 'until docker exec postgres pg_isready -U keycloak; do sleep 1; done' - - name: Run ${{ matrix.suite }} - run: > - BEHAT_SUITES="${{ matrix.suite }}" - ACCEPTANCE_TEST_TYPE=core-api - EXPECTED_FAILURES_FILE=tests/acceptance/expected-failures-API-on-OCIS-storage.md - python3 tests/acceptance/run-github.py + - name: Start Keycloak + if: matrix.keycloak == true + run: | + docker run -d --name keycloak --network host \ + -e OCIS_DOMAIN=https://localhost:9200 \ + -e KC_HOSTNAME=localhost \ + -e KC_PORT=8443 \ + -e KC_DB=postgres \ + -e "KC_DB_URL=jdbc:postgresql://localhost:5432/keycloak" \ + -e KC_DB_USERNAME=keycloak \ + -e KC_DB_PASSWORD=keycloak \ + -e KC_FEATURES=impersonation \ + -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ + -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \ + -e KC_HTTPS_CERTIFICATE_FILE=/keycloak-certs/keycloakcrt.pem \ + -e KC_HTTPS_CERTIFICATE_KEY_FILE=/keycloak-certs/keycloakkey.pem \ + -v "$(pwd)/keycloak-certs:/keycloak-certs:ro" \ + -v "$(pwd)/tests/config/drone/ocis-ci-realm.dist.json:/opt/keycloak/data/import/oCIS-realm.json:ro" \ + quay.io/keycloak/keycloak:26.2.5 \ + start-dev --proxy-headers xforwarded \ + --spi-connections-http-client-default-disable-trust-manager=true \ + --import-realm --health-enabled=true + timeout 300 bash -c 'until curl -skf https://localhost:8443/health/ready; do sleep 3; done' + echo "keycloak ready." - - name: Upload test logs - if: failure() - uses: actions/upload-artifact@v4 - with: - name: test-logs-${{ matrix.suite }} - path: tests/acceptance/output/ + - name: Run e2e-${{ matrix.suite }} + run: E2E_ARGS="${{ matrix.args }}" python3 tests/acceptance/run-e2e.py + env: + TIKA_NEEDED: ${{ matrix.tika == true && 'true' || 'false' }} + KEYCLOAK_NEEDED: ${{ matrix.keycloak == true && 'true' || 'false' }} all-acceptance-tests: - needs: [local-api-tests, cli-tests, core-api-tests] + needs: [e2e-tests] runs-on: ubuntu-latest if: always() steps: diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py new file mode 100755 index 00000000000..3f79ca0ce7a --- /dev/null +++ b/tests/acceptance/run-e2e.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 +""" +Run Playwright e2e tests against a local OCIS instance. + +Usage: E2E_ARGS='--run-part 1' python3 tests/acceptance/run-e2e.py +Optional: TIKA_NEEDED=true, KEYCLOAK_NEEDED=true +""" + +import json +import os +import sys +import shlex +import subprocess +import signal +import time +import shutil +from pathlib import Path + +WEB_REPO = "https://github.com/owncloud/web.git" + + +def wait_for(condition_fn, timeout: int, label: str) -> None: + deadline = time.time() + timeout + while not condition_fn(): + if time.time() > deadline: + print(f"Timeout waiting for {label}", file=sys.stderr) + sys.exit(1) + time.sleep(1) + + +def ocis_healthy(ocis_url: str) -> bool: + r = subprocess.run( + ["curl", "-sk", "-uadmin:admin", + f"{ocis_url}/graph/v1.0/users/admin", + "-w", "%{http_code}", "-o", "/dev/null"], + capture_output=True, text=True, + ) + return r.stdout.strip() == "200" + + +def run(cmd: list, env: dict = None, check: bool = True, cwd=None): + e = {**os.environ, **(env or {})} + return subprocess.run(cmd, env=e, check=check, cwd=cwd) + + +def main() -> int: + e2e_args = os.environ.get("E2E_ARGS", "").strip() + if not e2e_args: + print("E2E_ARGS is required, e.g. E2E_ARGS='--run-part 1' python3 run-e2e.py", + file=sys.stderr) + return 1 + + tika_needed = os.environ.get("TIKA_NEEDED", "").lower() == "true" + keycloak_needed = os.environ.get("KEYCLOAK_NEEDED", "").lower() == "true" + + repo_root = Path(__file__).resolve().parents[2] + ocis_bin = repo_root / "ocis/bin/ocis" + wrapper_bin = repo_root / "tests/ociswrapper/bin/ociswrapper" + ocis_url = "https://127.0.0.1:9200" + ocis_config_dir = Path.home() / ".ocis/config" + web_dir = repo_root / "webTestRunner" + + # build ocis + ociswrapper only if not already provided (e.g. via artifact) + if not ocis_bin.exists(): + run(["make", "-C", str(repo_root / "ocis"), "build"]) + if not wrapper_bin.exists(): + run(["make", "-C", str(repo_root / "tests/ociswrapper"), "build"], + env={"GOWORK": "off"}) + + # clone + install web only if not already provided (e.g. via artifact) + if not web_dir.exists(): + drone_env = {} + drone_env_file = repo_root / ".drone.env" + if drone_env_file.exists(): + for line in drone_env_file.read_text().splitlines(): + if "=" in line and not line.startswith("#"): + k, v = line.split("=", 1) + drone_env[k.strip()] = v.strip() + web_branch = drone_env.get("WEB_BRANCH", "master") + web_commitid = drone_env.get("WEB_COMMITID", "") + run(["git", "clone", "-b", web_branch, "--single-branch", "--no-tags", + WEB_REPO, str(web_dir)]) + if web_commitid: + subprocess.run(["git", "checkout", web_commitid], cwd=web_dir, check=True) + + if not (web_dir / "node_modules").exists(): + pkg_manager = json.loads((web_dir / "package.json").read_text()).get("packageManager", "pnpm") + run(["npm", "install", "--silent", "--global", "--force", pkg_manager]) + subprocess.run(["pnpm", "config", "set", "store-dir", "./.pnpm-store"], + cwd=web_dir, check=True) + subprocess.run(["pnpm", "install"], cwd=web_dir, check=True) + subprocess.run(["pnpm", "exec", "playwright", "install", "--with-deps", "chromium"], + cwd=web_dir, check=True) + + # init ocis + run([str(ocis_bin), "init", "--insecure", "true"]) + shutil.copy( + repo_root / "tests/config/drone/app-registry.yaml", + ocis_config_dir / "app-registry.yaml", + ) + + server_env = { + **os.environ, + # core — matches drone ocisServer() + "OCIS_URL": ocis_url, + "OCIS_CONFIG_DIR": str(ocis_config_dir), + "STORAGE_USERS_DRIVER": "ocis", + "PROXY_ENABLE_BASIC_AUTH": "true", + + "OCIS_LOG_LEVEL": "error", + "IDM_CREATE_DEMO_USERS": "true", + "IDM_ADMIN_PASSWORD": "admin", + "FRONTEND_SEARCH_MIN_LENGTH": "2", + "OCIS_ASYNC_UPLOADS": "true", + "OCIS_EVENTS_ENABLE_TLS": "false", + "NATS_NATS_HOST": "0.0.0.0", + "NATS_NATS_PORT": "9233", + "OCIS_JWT_SECRET": "some-ocis-jwt-secret", + "EVENTHISTORY_STORE": "memory", + "OCIS_TRANSLATION_PATH": str(repo_root / "tests/config/translations"), + "WEB_UI_CONFIG_FILE": str(repo_root / "tests/config/drone/ocis-config.json"), + "THUMBNAILS_TXT_FONTMAP_FILE": str(repo_root / "tests/config/drone/fontsMap.json"), + # extra_server_environment — matches drone e2eTestPipeline() + "OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST": str(repo_root / "tests/config/drone/banned-password-list.txt"), + "GRAPH_AVAILABLE_ROLES": "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5,a8d5fe5e-96e3-418d-825b-534dbdf22b99,fb6c3e19-e378-47e5-b277-9732f9de6e21,58c63c02-1d89-4572-916a-870abc5a1b7d,2d00ce52-1fc2-4dbc-8b95-a73b73395f5a,1c996275-f1c9-4e71-abdf-a42f6495e960,312c0871-5ef7-4b3a-85b6-0e4074c64049,aa97fe03-7980-45ac-9e50-b325749fd7e6,63e64e19-8d43-42ec-a738-2b6af2610efa", + "FRONTEND_CONFIGURABLE_NOTIFICATIONS": "true", + # debug addresses + "ACTIVITYLOG_DEBUG_ADDR": "0.0.0.0:9197", + "APP_PROVIDER_DEBUG_ADDR": "0.0.0.0:9165", + "APP_REGISTRY_DEBUG_ADDR": "0.0.0.0:9243", + "AUTH_BASIC_DEBUG_ADDR": "0.0.0.0:9147", + "AUTH_MACHINE_DEBUG_ADDR": "0.0.0.0:9167", + "AUTH_SERVICE_DEBUG_ADDR": "0.0.0.0:9198", + "CLIENTLOG_DEBUG_ADDR": "0.0.0.0:9260", + "EVENTHISTORY_DEBUG_ADDR": "0.0.0.0:9270", + "FRONTEND_DEBUG_ADDR": "0.0.0.0:9141", + "GATEWAY_DEBUG_ADDR": "0.0.0.0:9143", + "GRAPH_DEBUG_ADDR": "0.0.0.0:9124", + "GROUPS_DEBUG_ADDR": "0.0.0.0:9161", + "IDM_DEBUG_ADDR": "0.0.0.0:9239", + "IDP_DEBUG_ADDR": "0.0.0.0:9134", + "INVITATIONS_DEBUG_ADDR": "0.0.0.0:9269", + "NATS_DEBUG_ADDR": "0.0.0.0:9234", + "OCDAV_DEBUG_ADDR": "0.0.0.0:9163", + "OCM_DEBUG_ADDR": "0.0.0.0:9281", + "OCS_DEBUG_ADDR": "0.0.0.0:9114", + "POSTPROCESSING_DEBUG_ADDR": "0.0.0.0:9255", + "PROXY_DEBUG_ADDR": "0.0.0.0:9205", + "SEARCH_DEBUG_ADDR": "0.0.0.0:9224", + "SETTINGS_DEBUG_ADDR": "0.0.0.0:9194", + "SHARING_DEBUG_ADDR": "0.0.0.0:9151", + "SSE_DEBUG_ADDR": "0.0.0.0:9139", + "STORAGE_PUBLICLINK_DEBUG_ADDR": "0.0.0.0:9179", + "STORAGE_SHARES_DEBUG_ADDR": "0.0.0.0:9156", + "STORAGE_SYSTEM_DEBUG_ADDR": "0.0.0.0:9217", + "STORAGE_USERS_DEBUG_ADDR": "0.0.0.0:9159", + "THUMBNAILS_DEBUG_ADDR": "0.0.0.0:9189", + "USERLOG_DEBUG_ADDR": "0.0.0.0:9214", + "USERS_DEBUG_ADDR": "0.0.0.0:9145", + "WEB_DEBUG_ADDR": "0.0.0.0:9104", + "WEBDAV_DEBUG_ADDR": "0.0.0.0:9119", + "WEBFINGER_DEBUG_ADDR": "0.0.0.0:9279", + } + + if tika_needed: + server_env.update({ + "FRONTEND_FULL_TEXT_SEARCH_ENABLED": "true", + "SEARCH_EXTRACTOR_TYPE": "tika", + "SEARCH_EXTRACTOR_TIKA_TIKA_URL": "http://localhost:9998", + "SEARCH_EXTRACTOR_CS3SOURCE_INSECURE": "true", + }) + + if keycloak_needed: + server_env.update({ + "OCIS_EXCLUDE_RUN_SERVICES": "idp", + "PROXY_AUTOPROVISION_ACCOUNTS": "true", + "PROXY_ROLE_ASSIGNMENT_DRIVER": "oidc", + "OCIS_OIDC_ISSUER": "https://localhost:8443/realms/oCIS", + "PROXY_OIDC_REWRITE_WELLKNOWN": "true", + "WEB_OIDC_CLIENT_ID": "web", + "PROXY_USER_OIDC_CLAIM": "preferred_username", + "PROXY_USER_CS3_CLAIM": "username", + "OCIS_ADMIN_USER_ID": "", + "GRAPH_ASSIGN_DEFAULT_USER_ROLE": "false", + "GRAPH_USERNAME_MATCH": "none", + "PROXY_CSP_CONFIG_FILE_LOCATION": str(repo_root / "tests/config/drone/csp.yaml"), + "IDM_CREATE_DEMO_USERS": "false", + "OCIS_ADD_RUN_SERVICES": "ocm,notifications", + "OCIS_ENABLE_OCM": "true", + }) + + procs = [] + + print("Starting ocis...") + if keycloak_needed: + # external IdP: run ocis server directly (no ociswrapper) + ocis_proc = subprocess.Popen( + [str(ocis_bin), "server"], + env=server_env, + ) + else: + ocis_proc = subprocess.Popen( + [str(wrapper_bin), "serve", + "--bin", str(ocis_bin), + "--url", ocis_url, + "--admin-username", "admin", + "--admin-password", "admin"], + env=server_env, + ) + procs.append(ocis_proc) + + def cleanup(*_): + for p in procs: + try: + p.terminate() + except Exception: + pass + + signal.signal(signal.SIGTERM, cleanup) + signal.signal(signal.SIGINT, cleanup) + + try: + wait_for(lambda: ocis_healthy(ocis_url), 300, "ocis") + print("ocis ready.") + + playwright_env = { + **os.environ, + "BASE_URL_OCIS": ocis_url, + "HEADLESS": "true", + "RETRY": "1", + "SKIP_A11Y_TESTS": "true", + "REPORT_TRACING": "true", + "NODE_TLS_REJECT_UNAUTHORIZED": "0", + "BROWSER": "chromium", + } + + if keycloak_needed: + playwright_env.update({ + "KEYCLOAK": "true", + "KEYCLOAK_HOST": "localhost:8443", + }) + + print(f"Running e2e: {e2e_args}") + result = subprocess.run( + ["bash", "run-e2e.sh"] + shlex.split(e2e_args), + cwd=web_dir / "tests/e2e", + env=playwright_env, + ) + return result.returncode + + finally: + cleanup() + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/acceptance/run-e2e.sh b/tests/acceptance/run-e2e.sh new file mode 100755 index 00000000000..5ae1e2973fe --- /dev/null +++ b/tests/acceptance/run-e2e.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +OCIS_BIN="$REPO_ROOT/ocis/bin/ocis" +WRAPPER_BIN="$REPO_ROOT/tests/ociswrapper/bin/ociswrapper" +OCIS_URL="https://localhost:9200" +OCIS_CONFIG_DIR="$HOME/.ocis/config" +WEB_DIR="$REPO_ROOT/webTestRunner" + +: "${E2E_ARGS:?E2E_ARGS is required, e.g. E2E_ARGS='--run-part 1' bash run-e2e.sh}" + +# build ocis + ociswrapper +make -C "$REPO_ROOT/ocis" build +GOWORK=off make -C "$REPO_ROOT/tests/ociswrapper" build + +# clone owncloud/web (test runner lives there) +if [ ! -d "$WEB_DIR" ]; then + git clone --depth 1 https://github.com/owncloud/web.git "$WEB_DIR" +fi +cd "$WEB_DIR" +npm install -g pnpm +pnpm install + +# init + start ocis +"$OCIS_BIN" init --insecure true +cp "$REPO_ROOT/tests/config/drone/app-registry.yaml" "$OCIS_CONFIG_DIR/app-registry.yaml" + +OCIS_URL=$OCIS_URL \ +OCIS_CONFIG_DIR=$OCIS_CONFIG_DIR \ +STORAGE_USERS_DRIVER=ocis \ +PROXY_ENABLE_BASIC_AUTH=true \ +OCIS_EXCLUDE_RUN_SERVICES=idp \ +OCIS_LOG_LEVEL=error \ +IDM_CREATE_DEMO_USERS=true \ +IDM_ADMIN_PASSWORD=admin \ +OCIS_ASYNC_UPLOADS=true \ +OCIS_EVENTS_ENABLE_TLS=false \ +NATS_NATS_HOST=0.0.0.0 \ +NATS_NATS_PORT=9233 \ +OCIS_JWT_SECRET=some-ocis-jwt-secret \ +WEB_UI_CONFIG_FILE="$REPO_ROOT/tests/config/drone/ocis-config.json" \ + "$WRAPPER_BIN" serve \ + --bin "$OCIS_BIN" \ + --url "$OCIS_URL" \ + --admin-username admin \ + --admin-password admin & +WRAPPER_PID=$! +trap "kill $WRAPPER_PID 2>/dev/null || true" EXIT + +echo "Waiting for ocis..." +timeout 300 bash -c \ + "while [ \$(curl -sk -uadmin:admin $OCIS_URL/graph/v1.0/users/admin \ + -w %{http_code} -o /dev/null) != 200 ]; do sleep 1; done" +echo "ocis ready." + +# run playwright e2e tests +cd "$WEB_DIR/tests/e2e" +echo "Running e2e: $E2E_ARGS" +BASE_URL_OCIS=$OCIS_URL \ +HEADLESS=true \ +RETRY=1 \ +SKIP_A11Y_TESTS=true \ +REPORT_TRACING=true \ + bash run-e2e.sh $E2E_ARGS \ No newline at end of file From 05991d44dcc012ff21de33e9ac5efb1afec09dee Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 16:40:01 +0200 Subject: [PATCH 02/10] feat: [OCISDEV-744] e2e-test --- tests/acceptance/run-e2e.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py index 3f79ca0ce7a..459705a2db1 100755 --- a/tests/acceptance/run-e2e.py +++ b/tests/acceptance/run-e2e.py @@ -99,6 +99,24 @@ def main() -> int: ocis_config_dir / "app-registry.yaml", ) + # Patch web UI config: replace Drone Docker service name with our URL + drone_web_cfg = json.loads( + (repo_root / "tests/config/drone/ocis-config.json").read_text() + ) + + def _patch_urls(obj, old, new): + if isinstance(obj, dict): + return {k: _patch_urls(v, old, new) for k, v in obj.items()} + if isinstance(obj, list): + return [_patch_urls(v, old, new) for v in obj] + if isinstance(obj, str): + return obj.replace(old, new) + return obj + + gha_web_cfg = _patch_urls(drone_web_cfg, "https://ocis-server:9200", ocis_url) + gha_web_cfg_path = ocis_config_dir / "web-ui-config.json" + gha_web_cfg_path.write_text(json.dumps(gha_web_cfg, indent=2)) + server_env = { **os.environ, # core — matches drone ocisServer() @@ -118,7 +136,7 @@ def main() -> int: "OCIS_JWT_SECRET": "some-ocis-jwt-secret", "EVENTHISTORY_STORE": "memory", "OCIS_TRANSLATION_PATH": str(repo_root / "tests/config/translations"), - "WEB_UI_CONFIG_FILE": str(repo_root / "tests/config/drone/ocis-config.json"), + "WEB_UI_CONFIG_FILE": str(gha_web_cfg_path), "THUMBNAILS_TXT_FONTMAP_FILE": str(repo_root / "tests/config/drone/fontsMap.json"), # extra_server_environment — matches drone e2eTestPipeline() "OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST": str(repo_root / "tests/config/drone/banned-password-list.txt"), From 350d56f760376722ee464be8d2157828bc7846de Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 16:44:32 +0200 Subject: [PATCH 03/10] feat: [OCISDEV-744] e2e-test --- .github/workflows/acceptance-tests.yml | 102 ++++++++++++------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index efc8bc6e413..299dfb7c14e 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -365,57 +365,57 @@ jobs: TIKA_NEEDED: ${{ matrix.tika == true && 'true' || 'false' }} KEYCLOAK_NEEDED: ${{ matrix.keycloak == true && 'true' || 'false' }} - litmus: - name: litmus - needs: [build-and-test] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - cache: true - - name: Run litmus - run: python3 tests/acceptance/run-litmus.py - - cs3api: - name: cs3api - needs: [build-and-test] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - cache: true - - name: Run cs3api validator - run: python3 tests/acceptance/run-cs3api.py - - wopi-builtin: - name: wopi-builtin - needs: [build-and-test] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - cache: true - - name: Run WOPI validator (builtin) - run: python3 tests/acceptance/run-wopi.py --type builtin - - wopi-cs3: - name: wopi-cs3 - needs: [build-and-test] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - cache: true - - name: Run WOPI validator (cs3) - run: python3 tests/acceptance/run-wopi.py --type cs3 +# litmus: +# name: litmus +# needs: [build-and-test] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# cache: true +# - name: Run litmus +# run: python3 tests/acceptance/run-litmus.py +# +# cs3api: +# name: cs3api +# needs: [build-and-test] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# cache: true +# - name: Run cs3api validator +# run: python3 tests/acceptance/run-cs3api.py +# +# wopi-builtin: +# name: wopi-builtin +# needs: [build-and-test] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# cache: true +# - name: Run WOPI validator (builtin) +# run: python3 tests/acceptance/run-wopi.py --type builtin +# +# wopi-cs3: +# name: wopi-cs3 +# needs: [build-and-test] +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v4 +# - uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# cache: true +# - name: Run WOPI validator (cs3) +# run: python3 tests/acceptance/run-wopi.py --type cs3 all-acceptance-tests: needs: [e2e-tests] From 6380eb99c1344486ae498add2c0e38ee7fa01837 Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 18:20:49 +0200 Subject: [PATCH 04/10] feat: [OCISDEV-744] e2e-test --- .github/workflows/acceptance-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 299dfb7c14e..494c0b0cc1a 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -356,7 +356,8 @@ jobs: start-dev --proxy-headers xforwarded \ --spi-connections-http-client-default-disable-trust-manager=true \ --import-realm --health-enabled=true - timeout 300 bash -c 'until curl -skf https://localhost:8443/health/ready; do sleep 3; done' + timeout 300 bash -c 'until curl -skf https://localhost:8443/health/ready; do sleep 3; done' \ + || (echo "=== keycloak logs ===" && docker logs keycloak --tail 80 && exit 1) echo "keycloak ready." - name: Run e2e-${{ matrix.suite }} From 89fe4f8bc8647bbebef81814b708175b2c85013b Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 18:33:37 +0200 Subject: [PATCH 05/10] feat: [OCISDEV-744] e2e-test --- .github/workflows/acceptance-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 494c0b0cc1a..0b324a16c67 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -356,7 +356,7 @@ jobs: start-dev --proxy-headers xforwarded \ --spi-connections-http-client-default-disable-trust-manager=true \ --import-realm --health-enabled=true - timeout 300 bash -c 'until curl -skf https://localhost:8443/health/ready; do sleep 3; done' \ + timeout 300 bash -c 'until curl -skf https://localhost:9000/health/ready; do sleep 3; done' \ || (echo "=== keycloak logs ===" && docker logs keycloak --tail 80 && exit 1) echo "keycloak ready." From 58bffaa29ae7cde5e19015961c26d7b6e0921afa Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 18:53:22 +0200 Subject: [PATCH 06/10] feat: [OCISDEV-744] e2e-test --- tests/acceptance/run-e2e.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py index 459705a2db1..a7b09709bc6 100755 --- a/tests/acceptance/run-e2e.py +++ b/tests/acceptance/run-e2e.py @@ -203,8 +203,6 @@ def _patch_urls(obj, old, new): "GRAPH_USERNAME_MATCH": "none", "PROXY_CSP_CONFIG_FILE_LOCATION": str(repo_root / "tests/config/drone/csp.yaml"), "IDM_CREATE_DEMO_USERS": "false", - "OCIS_ADD_RUN_SERVICES": "ocm,notifications", - "OCIS_ENABLE_OCM": "true", }) procs = [] From a4834d8b1a39145ee06337a765623f472ea291e7 Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 19:24:19 +0200 Subject: [PATCH 07/10] feat: [OCISDEV-744] e2e-test --- tests/acceptance/run-e2e.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py index a7b09709bc6..18ae9fffdb5 100755 --- a/tests/acceptance/run-e2e.py +++ b/tests/acceptance/run-e2e.py @@ -99,6 +99,16 @@ def main() -> int: ocis_config_dir / "app-registry.yaml", ) + # Trust the self-signed cert system-wide so Chromium and node-fetch + # don't produce TLS handshake errors that load the server + ocis_cert = Path.home() / ".ocis/proxy/server.crt" + if ocis_cert.exists(): + subprocess.run( + ["sudo", "cp", str(ocis_cert), "/usr/local/share/ca-certificates/ocis.crt"], + check=True, + ) + subprocess.run(["sudo", "update-ca-certificates"], check=True) + # Patch web UI config: replace Drone Docker service name with our URL drone_web_cfg = json.loads( (repo_root / "tests/config/drone/ocis-config.json").read_text() @@ -246,7 +256,7 @@ def cleanup(*_): "RETRY": "1", "SKIP_A11Y_TESTS": "true", "REPORT_TRACING": "true", - "NODE_TLS_REJECT_UNAUTHORIZED": "0", + "NODE_EXTRA_CA_CERTS": str(ocis_cert), "BROWSER": "chromium", } From 6a051731d34dd677252d0ce7c587b5bed5085e2e Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 19:40:16 +0200 Subject: [PATCH 08/10] feat: [OCISDEV-744] e2e-test --- tests/acceptance/run-e2e.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py index 18ae9fffdb5..1bc51f57c74 100755 --- a/tests/acceptance/run-e2e.py +++ b/tests/acceptance/run-e2e.py @@ -28,13 +28,17 @@ def wait_for(condition_fn, timeout: int, label: str) -> None: time.sleep(1) -def ocis_healthy(ocis_url: str) -> bool: - r = subprocess.run( - ["curl", "-sk", "-uadmin:admin", - f"{ocis_url}/graph/v1.0/users/admin", - "-w", "%{http_code}", "-o", "/dev/null"], - capture_output=True, text=True, - ) +def ocis_healthy(ocis_url: str, use_basic_auth: bool = True) -> bool: + if use_basic_auth: + cmd = ["curl", "-sk", "-uadmin:admin", + f"{ocis_url}/graph/v1.0/users/admin", + "-w", "%{http_code}", "-o", "/dev/null"] + else: + # Keycloak mode: no local admin user, check unauthenticated endpoint + cmd = ["curl", "-sk", + f"{ocis_url}/.well-known/openid-configuration", + "-w", "%{http_code}", "-o", "/dev/null"] + r = subprocess.run(cmd, capture_output=True, text=True) return r.stdout.strip() == "200" @@ -246,7 +250,7 @@ def cleanup(*_): signal.signal(signal.SIGINT, cleanup) try: - wait_for(lambda: ocis_healthy(ocis_url), 300, "ocis") + wait_for(lambda: ocis_healthy(ocis_url, use_basic_auth=not keycloak_needed), 300, "ocis") print("ocis ready.") playwright_env = { From ea7c35d2f464cf6d8856e659088f8c8c19332712 Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 19:54:29 +0200 Subject: [PATCH 09/10] feat: [OCISDEV-744] e2e-test --- .github/workflows/acceptance-tests.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 0b324a16c67..a283f4fb23e 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -337,8 +337,11 @@ jobs: - name: Start Keycloak if: matrix.keycloak == true run: | + # Patch realm: replace Drone Docker hostname with localhost IP + sed 's|https://ocis-server:9200|https://127.0.0.1:9200|g' \ + tests/config/drone/ocis-ci-realm.dist.json > /tmp/ocis-realm.json docker run -d --name keycloak --network host \ - -e OCIS_DOMAIN=https://localhost:9200 \ + -e OCIS_DOMAIN=https://127.0.0.1:9200 \ -e KC_HOSTNAME=localhost \ -e KC_PORT=8443 \ -e KC_DB=postgres \ @@ -351,7 +354,7 @@ jobs: -e KC_HTTPS_CERTIFICATE_FILE=/keycloak-certs/keycloakcrt.pem \ -e KC_HTTPS_CERTIFICATE_KEY_FILE=/keycloak-certs/keycloakkey.pem \ -v "$(pwd)/keycloak-certs:/keycloak-certs:ro" \ - -v "$(pwd)/tests/config/drone/ocis-ci-realm.dist.json:/opt/keycloak/data/import/oCIS-realm.json:ro" \ + -v "/tmp/ocis-realm.json:/opt/keycloak/data/import/oCIS-realm.json:ro" \ quay.io/keycloak/keycloak:26.2.5 \ start-dev --proxy-headers xforwarded \ --spi-connections-http-client-default-disable-trust-manager=true \ From 42647a0cb7831cb7c7742149da3665d0f670dc76 Mon Sep 17 00:00:00 2001 From: Michal Klos Date: Tue, 31 Mar 2026 20:32:56 +0200 Subject: [PATCH 10/10] feat: [OCISDEV-744] e2e-test --- tests/acceptance/run-e2e.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/acceptance/run-e2e.py b/tests/acceptance/run-e2e.py index 1bc51f57c74..604ec1dbaa9 100755 --- a/tests/acceptance/run-e2e.py +++ b/tests/acceptance/run-e2e.py @@ -216,6 +216,7 @@ def _patch_urls(obj, old, new): "GRAPH_ASSIGN_DEFAULT_USER_ROLE": "false", "GRAPH_USERNAME_MATCH": "none", "PROXY_CSP_CONFIG_FILE_LOCATION": str(repo_root / "tests/config/drone/csp.yaml"), + "KEYCLOAK_DOMAIN": "localhost:8443", "IDM_CREATE_DEMO_USERS": "false", })