diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 1c43b147996..fc25b17448b 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -5,36 +5,38 @@ 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 + # coding-standard: + # name: coding-standard + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + # - name: Install PHP 8.4 + # run: | + # sudo add-apt-repository -y ppa:ondrej/php + # sudo apt-get update -qq + # sudo apt-get install -y php8.4 php8.4-curl php8.4-xml php8.4-mbstring php8.4-zip php8.4-ldap php8.4-gd + # sudo update-alternatives --set php /usr/bin/php8.4 + # curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=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 @@ -44,48 +46,48 @@ jobs: - 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 + # 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 - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "24" + # - 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: Enable pnpm + # run: corepack enable && corepack prepare pnpm@10.28.1 --activate - - name: Generate nodejs - run: make ci-node-generate + # - name: Generate nodejs + # run: make ci-node-generate - - name: Generate go - run: make ci-go-generate + # - name: Generate go + # run: make ci-go-generate - - name: Vulnerability scan - run: make govulncheck + # - name: Vulnerability scan + # run: make govulncheck - - name: Lint - run: make ci-golangci-lint + # - name: Lint + # run: make ci-golangci-lint - - name: Build ocis - run: make -C ocis build + # - name: Build ocis + # run: make -C ocis build - - name: Build debug binary - run: make -C ocis build-debug + # - name: Build debug binary + # run: make -C ocis build-debug - - name: Unit tests - run: make test + # - name: Unit tests + # run: make test local-api-tests: name: ${{ matrix.suite }} - needs: [build-and-test] + needs: [] #[build-and-test] runs-on: ubuntu-latest strategy: fail-fast: false @@ -113,7 +115,7 @@ jobs: - apiActivities # search - apiSearch1 - # - apiSearch2 + - apiSearch2 - apiSearchContent # needs Tika # sharing - apiSharingNgShares @@ -169,17 +171,21 @@ jobs: } ' - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 - with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer + - name: Install PHP 8.4 + run: | + sudo add-apt-repository -y ppa:ondrej/php + sudo apt-get update -qq + sudo apt-get install -y php8.4 php8.4-curl php8.4-xml php8.4-mbstring php8.4-zip php8.4-ldap php8.4-gd + sudo update-alternatives --set php /usr/bin/php8.4 + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + php -v + composer --version - name: Run ${{ matrix.suite }} run: BEHAT_SUITES=${{ matrix.suite }} python3 tests/acceptance/run-github.py cli-tests: - needs: [build-and-test] + needs: [] # [build-and-test] name: ${{ matrix.suite }} runs-on: ubuntu-latest strategy: @@ -201,18 +207,22 @@ jobs: - 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: Install PHP 8.4 + run: | + sudo add-apt-repository -y ppa:ondrej/php + sudo apt-get update -qq + sudo apt-get install -y php8.4 php8.4-curl php8.4-xml php8.4-mbstring php8.4-zip php8.4-ldap php8.4-gd + sudo update-alternatives --set php /usr/bin/php8.4 + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + php -v + composer --version - 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] + needs: [] # [build-and-test] runs-on: ubuntu-latest strategy: fail-fast: false @@ -262,11 +272,13 @@ jobs: } ' - - uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 - with: - php-version: "8.4" - extensions: curl, xml, mbstring, zip - tools: composer + - name: Install PHP 8.4 + run: | + sudo add-apt-repository -y ppa:ondrej/php + sudo apt-get update -qq + sudo apt-get install -y php8.4 php8.4-curl php8.4-xml php8.4-mbstring php8.4-zip php8.4-ldap php8.4-gd + sudo update-alternatives --set php /usr/bin/php8.4 + curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - name: Run ${{ matrix.suite }} run: > @@ -275,121 +287,121 @@ jobs: WITH_REMOTE_PHP=true python3 tests/acceptance/run-github.py - e2e-tests: - name: e2e-${{ matrix.suite }} - needs: [build-and-test] - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - 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: Setup pnpm - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 - with: - version: "10.28.1" - - name: Generate code - run: | - pnpm config set store-dir ./.pnpm-store - make ci-node-generate - env: - CHROMEDRIVER_SKIP_DOWNLOAD: "true" - - - name: Cache Playwright Chromium - uses: actions/cache@v4 - with: - path: ~/.cache/ms-playwright - key: playwright-chromium-${{ hashFiles('.drone.env') }} - - # --- 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." - - # --- Keycloak (keycloak suite only) --- - - name: Generate Keycloak certs - if: matrix.keycloak == true - run: | - 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 - - - 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: 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://127.0.0.1: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 "/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 \ - --import-realm --health-enabled=true - 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." - - - 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' }} + # e2e-tests: + # name: e2e-${{ matrix.suite }} + # needs: [build-and-test] + # runs-on: ubuntu-latest + # strategy: + # fail-fast: false + # matrix: + # 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: Setup pnpm + # uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 + # with: + # version: "10.28.1" + # - name: Generate code + # run: | + # pnpm config set store-dir ./.pnpm-store + # make ci-node-generate + # env: + # CHROMEDRIVER_SKIP_DOWNLOAD: "true" + + # - name: Cache Playwright Chromium + # uses: actions/cache@v4 + # with: + # path: ~/.cache/ms-playwright + # key: playwright-chromium-${{ hashFiles('.drone.env') }} + + # # --- 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." + + # # --- Keycloak (keycloak suite only) --- + # - name: Generate Keycloak certs + # if: matrix.keycloak == true + # run: | + # 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 + + # - 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: 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://127.0.0.1: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 "/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 \ + # --import-realm --health-enabled=true + # 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." + + # - 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' }} litmus: name: litmus - needs: [build-and-test] + needs: [] # [build-and-test] runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -402,7 +414,7 @@ jobs: cs3api: name: cs3api - needs: [build-and-test] + needs: [] # [build-and-test] runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -415,7 +427,7 @@ jobs: wopi-builtin: name: wopi-builtin - needs: [build-and-test] + needs: [] # [build-and-test] runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -428,7 +440,7 @@ jobs: wopi-cs3: name: wopi-cs3 - needs: [build-and-test] + needs: [] # [build-and-test] runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -440,7 +452,7 @@ jobs: run: python3 tests/acceptance/run-wopi.py --type cs3 all-acceptance-tests: - needs: [local-api-tests, cli-tests, core-api-tests, litmus, cs3api, wopi-builtin, wopi-cs3, e2e-tests] + needs: [local-api-tests, cli-tests, wopi-cs3] # [local-api-tests, cli-tests, core-api-tests, litmus, cs3api, wopi-builtin, wopi-cs3, e2e-tests] runs-on: ubuntu-latest if: always() steps: diff --git a/tests/acceptance/bootstrap/SearchContext.php b/tests/acceptance/bootstrap/SearchContext.php index 06ff0cac318..54c47db4494 100644 --- a/tests/acceptance/bootstrap/SearchContext.php +++ b/tests/acceptance/bootstrap/SearchContext.php @@ -38,6 +38,36 @@ class SearchContext implements Context { private FeatureContext $featureContext; + /** + * Retry search until results are non-empty or timeout is reached. + * Indexing of newly uploaded files in ocis is async, so a single + * fixed sleep is not reliable — poll instead. + */ + private function searchWithRetry( + string $user, + string $pattern, + ?string $limit = null, + ?string $scopeType = null, + ?string $scope = null, + ?string $spaceName = null, + ?TableNode $properties = null, + ): ResponseInterface { + // Indexing is async — poll until results appear. + // Initial wait 3s, then retry every 2s, up to ~13s total. + $maxAttempts = STANDARD_RETRY_COUNT; + $response = null; + for ($attempt = 0; $attempt < $maxAttempts; $attempt++) { + \sleep($attempt === 0 ? 3 : 2); + $response = $this->searchFiles($user, $pattern, $limit, $scopeType, $scope, $spaceName, $properties); + $parsed = HttpRequestHelper::parseResponseAsXml($response); + if (\is_array($parsed) && isset($parsed["value"]) && !empty($parsed["value"])) { + return $response; + } + } + // return last response even if empty — let the assertion step produce the failure message + return $response; + } + /** * @param string $user * @param string $pattern @@ -146,10 +176,7 @@ public function userSearchesUsingWebDavAPI( ?string $limit = null, ?TableNode $properties = null, ): void { - // NOTE: because indexing of newly uploaded files or directories with ocis is decoupled and occurs asynchronously - // short wait is necessary before searching - sleep(5); - $response = $this->searchFiles($user, $pattern, $limit, null, null, null, $properties); + $response = $this->searchWithRetry($user, $pattern, $limit, null, null, null, $properties); $this->featureContext->setResponse($response); } @@ -269,10 +296,7 @@ public function userSearchesInsideFolderOrSpaceUsingWebDavAPI( string $scope, ?string $spaceName = null, ): void { - // NOTE: since indexing of newly uploaded files or directories with ocis is decoupled and occurs asynchronously, - // a short wait is necessary before searching - sleep(5); - $response = $this-> searchFiles($user, $pattern, null, $scopeType, $scope, $spaceName); + $response = $this->searchWithRetry($user, $pattern, null, $scopeType, $scope, $spaceName); $this->featureContext->setResponse($response); } }