From 16f78eef30166c7b049a8d26bd024fd2d0aa4a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:06:27 +0200 Subject: [PATCH 1/4] ci: run core's acceptance suite against the published image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build pipeline only proves the image builds, passes Trivy and answers /status.php. There is no functional test of the shipped artifact anywhere, so regressions in the image's own layers - entrypoint scripts, config template, app bundle - are only found by hand. Add a reusable acceptance workflow that runs core's Behat suite against a published owncloud/server tag. The suite talks to the container over HTTP: run.sh --remote proxies every occ call through the testing app's OCS endpoint, so no shell access to the server is needed. Test code comes from the release QA tarball, which is the same build as the shipped code and carries a version-matched testing app. This is a port of the pipeline the retired .drone.star already ran, so the shape is proven; the notable adaptations for Actions are: - Host networking throughout. The suite hands federated addresses such as localhost:8081 to the *server*, so they must resolve to the peer from inside the container. Actions service containers get a bridge network, where they would resolve to the container itself. - The testing app is bind-mounted from the QA tarball rather than installed from its GitHub release asset, which was last rebuilt in 2022. The mount must be writable because 25-chown.sh chowns the app tree at every start. - The enabled-app set is pinned explicitly to core CI's, since the Complete bundle default-enables a different set and a mismatch produces failures that look like server regressions. Wired into main.yml on master only, after build, defaulting to @smokeTest so the ~4 min PR loop is untouched; the full set is available via the dispatch inputs. 10.16.3 is left out because 10.x ships no QA tarball. Verified against owncloud/server:11.0.0-rc3 locally: a smoke shard with both servers up reports 76 scenarios, 76 passed, 0 failed, including apiFederationToRoot1. Co-Authored-By: Claude Opus 5 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .github/workflows/acceptance.yml | 400 +++++++++++++++++++++++++++++++ .github/workflows/main.yml | 41 ++++ 2 files changed, 441 insertions(+) create mode 100644 .github/workflows/acceptance.yml diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml new file mode 100644 index 0000000..bd64239 --- /dev/null +++ b/.github/workflows/acceptance.yml @@ -0,0 +1,400 @@ +name: Acceptance tests + +# Runs core's Behat acceptance suite against a *published* owncloud/server image. +# +# This is a functional test of the shipped artifact, which the build pipeline +# (docker-build.yml) does not provide - it only proves the image builds, passes +# Trivy and answers /status.php. +# +# The suite talks to the container over HTTP: run.sh --remote proxies every occ +# call through the testing app's OCS endpoint, so no shell access to the server +# is needed. This is the same arrangement the retired .drone.star pipeline used. + +on: + workflow_call: + inputs: + image: + description: Image under test + required: false + type: string + default: owncloud/server + image-tag: + description: Tag of the image under test, e.g. 11.0.0-rc3-20260729 + required: true + type: string + qa-tarball: + description: > + URL of the release QA tarball. It carries the acceptance suite *and* + the testing app, both version-matched to the image. + required: true + type: string + core-ref: + description: core git ref used to fetch the behat composer manifest, e.g. v11.0.0-rc3 + required: true + type: string + php-version: + description: PHP version used to run behat + required: false + type: string + default: "8.3" + test-type: + description: api or cli + required: false + type: string + default: api + filter-tags: + description: Behat tag filter; empty runs every scenario of the type + required: false + type: string + default: "@smokeTest" + shards: + description: Number of parallel shards to split the suites across + required: false + type: number + default: 10 + with-federation: + description: Start a second server so the federation suites can run + required: false + type: boolean + default: true + additional-packages: + description: Extra apt packages for the runner - space separated + required: false + type: string + default: "" + + workflow_dispatch: + inputs: + image: + description: Image under test + required: false + type: string + default: owncloud/server + image-tag: + description: Tag of the image under test, e.g. 11.0.0-rc3-20260729 + required: true + type: string + qa-tarball: + description: URL of the release QA tarball + required: true + type: string + core-ref: + description: core git ref for the behat composer manifest, e.g. v11.0.0-rc3 + required: true + type: string + php-version: + description: PHP version used to run behat + required: false + type: string + default: "8.3" + test-type: + description: Which suites to run + required: false + type: choice + options: + - api + - cli + default: api + filter-tags: + description: Behat tag filter; clear this to run the full set + required: false + type: string + default: "@smokeTest" + shards: + description: Number of parallel shards + required: false + type: number + default: 10 + with-federation: + description: Start a second server for the federation suites + required: false + type: boolean + default: true + additional-packages: + description: Extra apt packages for the runner - space separated + required: false + type: string + default: "" + +permissions: + contents: read + +env: + # Core's own CI installs from core's git tree, where Installer::getShippedApps() + # enables every app carrying - 11 apps, notably including + # comments, systemtags, files_external and updatenotification - and then enables + # federatedfilesharing and testing on top. The Complete bundle in the image + # default-enables a different, larger set, so pin the CI-equivalent list + # explicitly. Disabling files_external here, for instance, makes apiAuth report + # OCS 999 instead of the expected 997 on /apps/files_external/api/v1/mounts - + # a failure that looks like a server regression but is a harness error. + APPS_ENABLE: comments,dav,federation,federatedfilesharing,files,files_external,files_sharing,files_trashbin,files_versions,provisioning_api,systemtags,testing,updatenotification + # Image defaults minus core defaults. run.sh disables firstrunwizard and + # notifications itself, but do it up front so both servers start from the + # same state regardless of which suites a shard happens to get. + APPS_DISABLE: activity,configreport,diagnostics,files_mediaviewer,files_pdfviewer,files_texteditor,firstrunwizard,market,notifications + +jobs: + # A matrix cannot take a numeric range, so materialise 1..shards as JSON. + prepare: + runs-on: ubuntu-latest + outputs: + parts: ${{ steps.parts.outputs.parts }} + steps: + - name: Compute shard list + id: parts + env: + SHARDS: ${{ inputs.shards }} + run: | + echo "parts=$(seq -s, 1 "${SHARDS}" | sed 's/^/[/;s/$/]/')" >> "$GITHUB_OUTPUT" + + acceptance: + needs: prepare + name: ${{ inputs.test-type }}-${{ matrix.part }} + runs-on: ubuntu-latest + strategy: + # One red shard must not hide the state of the others. + fail-fast: false + matrix: + part: ${{ fromJSON(needs.prepare.outputs.parts) }} + steps: + - name: Install runner packages + env: + ADDITIONAL_PACKAGES: ${{ inputs.additional-packages }} + run: | + sudo apt-get update + # run.sh parses the OCS responses of every remote occ call with xmllint. + # ADDITIONAL_PACKAGES is a space separated list, so it must word-split. + # shellcheck disable=SC2086 + sudo apt-get install -y libxml2-utils ${ADDITIONAL_PACKAGES} + + - name: Setup PHP + uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2.37.2 + with: + php-version: ${{ inputs.php-version }} + # Extensions required by the behat dependency tree (ldap for the + # laminas-ldap based provisioning steps). + extensions: ctype, curl, dom, iconv, json, ldap, libxml, mbstring, phar, tokenizer, xmlreader, xmlwriter, zip + ini-values: memory_limit=2048M + env: + fail-fast: true + + - name: Fetch the acceptance suite + env: + QA_TARBALL: ${{ inputs.qa-tarball }} + run: | + curl -sSfL -o owncloud-qa.tar.bz2 "${QA_TARBALL}" + tar -xjf owncloud-qa.tar.bz2 --strip 1 + rm -f owncloud-qa.tar.bz2 + cat version.php + + - name: Install behat + env: + CORE_REF: ${{ inputs.core-ref }} + run: | + # The QA tarball ships the suite but not the behat manifest, so take it + # from the matching core tag. + mkdir -p vendor-bin/behat + curl -sSfL -o vendor-bin/behat/composer.json \ + "https://raw.githubusercontent.com/owncloud/core/${CORE_REF}/vendor-bin/behat/composer.json" + composer install --no-interaction --working-dir=vendor-bin/behat + + - name: Stage the testing app + run: | + # The testing app provides the occ-over-HTTP transport the suite needs, + # and it is not enabled in the image by default. Take the copy from the + # QA tarball rather than the app's GitHub "latest" release asset: that + # asset was last rebuilt in 2022 and is not version-matched to the + # image, whereas the tarball ships the same build as the shipped code + # (and, unlike the release asset, a signature.json that satisfies the + # integrity check). + # + # Staged outside the workspace and bind-mounted writable: 25-chown.sh + # chowns the whole app tree at every start and the entrypoint aborts + # with exit 123 if that fails, so a read-only mount kills the server. + mkdir -p "${RUNNER_TEMP}/apps" + cp -r apps/testing "${RUNNER_TEMP}/apps/testing" + + - name: Start MariaDB and Redis + run: | + # Host networking throughout: the suite hands federated addresses such + # as localhost:8081 to the *server*, so those names must resolve to the + # peer from inside the container too. With bridge networking they would + # resolve to the container itself. + docker run -d --name mariadb --network host \ + -e MARIADB_ROOT_PASSWORD=owncloud \ + -e MARIADB_USER=owncloud \ + -e MARIADB_PASSWORD=owncloud \ + -e MARIADB_DATABASE=owncloud \ + mariadb:10.6 --max-allowed-packet=128M --innodb-log-file-size=64M + + # File locking via Redis, as the Drone pipeline did. The DB locking + # provider produced spurious HTTP 423 responses in local runs. + docker run -d --name redis --network host redis:8 + + for _ in $(seq 60); do + docker exec mariadb healthcheck.sh --connect --innodb_initialized && break + sleep 2 + done + docker exec mariadb mariadb -uroot -powncloud -e \ + "CREATE DATABASE IF NOT EXISTS owncloud_fed CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; + GRANT ALL PRIVILEGES ON owncloud_fed.* TO 'owncloud'@'%'; + FLUSH PRIVILEGES;" + + - name: Start the email server + run: | + docker run -d --name inbucket --network host \ + -e INBUCKET_SMTP_ADDR=:2500 \ + -e INBUCKET_WEB_ADDR=:9000 \ + -e INBUCKET_POP3_ADDR=:1100 \ + -e INBUCKET_STORAGE_MAILBOXMSGCAP=300 \ + inbucket/inbucket + + - name: Write the server environment + run: | + # These settings must arrive as environment variables, not via occ: + # 20-config.sh renders them into overwrite.config.php, which + # Config::readData() merges *after* config.php and which therefore + # overrides anything config:system:set writes. + cat > server.env <> server.env + + - name: Start the server under test + env: + IMAGE: ${{ inputs.image }}:${{ inputs.image-tag }} + run: | + docker run -d --name server --network host --env-file server.env \ + -e APACHE_LISTEN=8080 \ + -e OWNCLOUD_DOMAIN=localhost:8080 \ + -e OWNCLOUD_DB_NAME=owncloud \ + -v "${RUNNER_TEMP}/apps/testing:/var/www/owncloud/apps/testing" \ + "${IMAGE}" + + - name: Start the federated server + if: ${{ inputs.with-federation }} + env: + IMAGE: ${{ inputs.image }}:${{ inputs.image-tag }} + run: | + docker run -d --name server-fed --network host --env-file server.env \ + -e APACHE_LISTEN=8081 \ + -e OWNCLOUD_DOMAIN=localhost:8081 \ + -e OWNCLOUD_DB_NAME=owncloud_fed \ + -v "${RUNNER_TEMP}/apps/testing:/var/www/owncloud/apps/testing" \ + "${IMAGE}" + + - name: Wait for the servers + env: + WITH_FEDERATION: ${{ inputs.with-federation }} + run: | + ports=8080 + [[ "${WITH_FEDERATION}" == "true" ]] && ports="8080 8081" + + for port in ${ports}; do + echo "Waiting for localhost:${port}..." + for _ in $(seq 120); do + if curl -sSf "http://localhost:${port}/status.php" -o "status-${port}.json"; then + break + fi + sleep 5 + done + # Fail here rather than letting behat fail confusingly further down. + cat "status-${port}.json" + jq -e '.installed == true and .maintenance == false' "status-${port}.json" + done + + - name: Verify the occ transport + env: + WITH_FEDERATION: ${{ inputs.with-federation }} + run: | + ports=8080 + [[ "${WITH_FEDERATION}" == "true" ]] && ports="8080 8081" + + for port in ${ports}; do + # Every occ call the suite makes goes through this endpoint. If it + # does not answer, nothing downstream works. + code=$(curl -sS -u admin:admin -X POST \ + -d "command=status" \ + "http://localhost:${port}/ocs/v2.php/apps/testing/api/v1/occ" \ + | xmllint --xpath "string(ocs/data/code)" -) + echo "localhost:${port} occ status exit code: ${code}" + [[ "${code}" == "0" ]] + done + + - name: Report the enabled apps + run: | + # The app baseline decides whether the results mean anything, so make + # it visible in the log rather than implied by the env file. + curl -sS -u admin:admin -X POST -d "command=app:list" \ + "http://localhost:8080/ocs/v2.php/apps/testing/api/v1/occ" \ + | xmllint --xpath "string(ocs/data/stdOut)" - + + - name: Run the acceptance tests + env: + TEST_SERVER_URL: http://localhost:8080 + TEST_SERVER_FED_URL: ${{ inputs.with-federation && 'http://localhost:8081' || '' }} + # Where the system under test reaches inbucket, and where the suite does. + EMAIL_HOST: 127.0.0.1 + LOCAL_EMAIL_HOST: 127.0.0.1 + SKELETON_DIR: /var/www/owncloud/apps/testing/data/apiSkeleton + NORERUN: "true" + PLAIN_OUTPUT: "true" + TEST_TYPE: ${{ inputs.test-type }} + FILTER_TAGS: ${{ inputs.filter-tags }} + PART: ${{ matrix.part }} + SHARDS: ${{ inputs.shards }} + run: | + declare -a tags=() + [[ -n "${FILTER_TAGS}" ]] && tags=(--tags "${FILTER_TAGS}") + + bash tests/acceptance/run.sh --remote --type "${TEST_TYPE}" \ + "${tags[@]}" --part "${PART}" "${SHARDS}" + + - name: Collect server logs + if: failure() + run: | + for name in server server-fed; do + docker inspect "${name}" >/dev/null 2>&1 || continue + docker logs "${name}" > "docker-${name}.log" 2>&1 + docker exec "${name}" sh -c 'tail -n 2000 /mnt/data/files/owncloud.log' \ + > "owncloud-${name}.log" 2>&1 || true + done + + - name: Upload logs + if: failure() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: logs-${{ inputs.test-type }}-${{ matrix.part }} + path: | + docker-*.log + owncloud-*.log + status-*.json + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fac1d49..9587bf8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,6 +40,11 @@ jobs: strategy: matrix: release: + # No qa-tarball, so the acceptance job skips this release. v10.16.4 + # does publish one, and its run.sh takes --remote and --part just like + # 11.x, so wiring it up is a small follow-up - but it has not been + # tried against this image yet, and 10.x uses config/behat.yml where + # 11.x uses behat.php. Verify before adding it. - version: 10.16.4 tarball: https://github.com/owncloud/core/releases/download/v10.16.4/owncloud-complete-20260729.tar.bz2 base: v22.04 @@ -51,10 +56,46 @@ jobs: smoke-version-jq: ".versionstring" - version: 11.0.0-rc3 tarball: https://github.com/owncloud/core/releases/download/v11.0.0-rc3/owncloud-complete-20260729.tar.bz2 + qa-tarball: https://github.com/owncloud/core/releases/download/v11.0.0-rc3/owncloud-complete-20260729-qa.tar.bz2 + core-ref: v11.0.0-rc3 base: v24.04 trivy-ignore: v24.04/11.0.0-rc3/.trivyignore smoke-version-jq: "" + # Functional test of the published image. Deliberately not run on pull + # requests: those are mostly renovate digest bumps and the ~4 min build loop + # should stay that fast. Run the full set manually via the acceptance + # workflow's dispatch inputs. + acceptance: + needs: build + if: github.ref == 'refs/heads/master' + uses: ./.github/workflows/acceptance.yml + with: + image: owncloud/${{ github.event.repository.name }} + # The build tags with the version and, via build-date-tag, a dated + # variant. The plain version tag is the one that always exists. + image-tag: ${{ matrix.release.version }} + qa-tarball: ${{ matrix.release.qa-tarball }} + core-ref: ${{ matrix.release.core-ref }} + test-type: ${{ matrix.suites.type }} + shards: ${{ matrix.suites.shards }} + + strategy: + fail-fast: false + matrix: + # Shards split by suite count, so keep the count at or below the number + # of suites - 61 api and 9 cli in 11.x - otherwise the surplus shards + # start a full server stack only to find they have nothing to run. + suites: + - type: api + shards: 10 + - type: cli + shards: 3 + release: + - version: 11.0.0-rc3 + qa-tarball: https://github.com/owncloud/core/releases/download/v11.0.0-rc3/owncloud-complete-20260729-qa.tar.bz2 + core-ref: v11.0.0-rc3 + update-docker-hub-description: needs: build if: github.ref == 'refs/heads/master' From e69f711b69ea028d6513a1ca6d1c436a0da67609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:26:17 +0200 Subject: [PATCH 2/4] ci: satisfy editorconfig in the fed database setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit editorconfig-checker rejected the continuation lines of the SQL passed to mariadb: they were aligned to the opening quote, which is not a multiple of the 2-space indent width. Move the statements onto stdin via a heredoc. Repeated -e flags are not an option - mariadb concatenates their values into a single statement, so the GRANT would have been parsed as part of the CREATE DATABASE and the fed database would silently never have been created. Co-Authored-By: Claude Opus 5 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .github/workflows/acceptance.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index bd64239..abf6afb 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -236,10 +236,13 @@ jobs: docker exec mariadb healthcheck.sh --connect --innodb_initialized && break sleep 2 done - docker exec mariadb mariadb -uroot -powncloud -e \ - "CREATE DATABASE IF NOT EXISTS owncloud_fed CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; - GRANT ALL PRIVILEGES ON owncloud_fed.* TO 'owncloud'@'%'; - FLUSH PRIVILEGES;" + # Statements on stdin rather than repeated -e flags: mariadb + # concatenates multiple -e values into a single statement. + docker exec -i mariadb mariadb -uroot -powncloud <<'SQL' + CREATE DATABASE IF NOT EXISTS owncloud_fed CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; + GRANT ALL PRIVILEGES ON owncloud_fed.* TO 'owncloud'@'%'; + FLUSH PRIVILEGES; + SQL - name: Start the email server run: | From 5ba833f7d31a8dfc97ddc93bf718f99a8cc07262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Thu, 30 Jul 2026 10:56:40 +0200 Subject: [PATCH 3/4] ci: temporarily run the full acceptance suite on this PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit workflow_dispatch cannot reach acceptance.yml yet: GitHub only registers dispatchable workflows from the default branch, and the file exists only on this branch. The acceptance job is also gated to master, so it showed up as "acceptance in 0s" on the PR. Let it run on pull_request and drop the @smokeTest filter so this PR produces authoritative 11.0.0-rc3 numbers. Shards go to 20 api / 9 cli: run.sh slices by suite count distributing whole suites, so 20 and 9 are the maximum useful splits for 61 and 9 suites, and no shard ends up empty. The cli set carries only 3 @smokeTest scenarios out of 386, which is why filtering it is pointless. Temporary - the PR loop is slow while this is in place. Revisit before merge. Co-Authored-By: Claude Opus 5 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .github/workflows/main.yml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9587bf8..df6fa73 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,13 +62,15 @@ jobs: trivy-ignore: v24.04/11.0.0-rc3/.trivyignore smoke-version-jq: "" - # Functional test of the published image. Deliberately not run on pull - # requests: those are mostly renovate digest bumps and the ~4 min build loop - # should stay that fast. Run the full set manually via the acceptance - # workflow's dispatch inputs. + # Functional test of the published image. + # + # TEMPORARY: also runs on pull requests, and runs the *full* suite rather than + # @smokeTest, so this PR can produce authoritative 11.0.0-rc3 results before + # the trigger policy is settled. While this is in place the PR loop is slow - + # 29 shards instead of nothing. Revisit before merge. acceptance: needs: build - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/master' || github.event_name == 'pull_request' uses: ./.github/workflows/acceptance.yml with: image: owncloud/${{ github.event.repository.name }} @@ -79,18 +81,23 @@ jobs: core-ref: ${{ matrix.release.core-ref }} test-type: ${{ matrix.suites.type }} shards: ${{ matrix.suites.shards }} + # Empty overrides the workflow's @smokeTest default and runs everything. + # The cli set only carries 3 @smokeTest scenarios out of 386, so a + # smoke-filtered cli run would say nothing at all. + filter-tags: "" strategy: fail-fast: false matrix: - # Shards split by suite count, so keep the count at or below the number - # of suites - 61 api and 9 cli in 11.x - otherwise the surplus shards - # start a full server stack only to find they have nothing to run. + # Shards split by suite count, distributing whole suites, so keep the + # count at or below the number of suites - 61 api and 9 cli in 11.x - + # otherwise the surplus shards start a full server stack only to find + # they have nothing to run. suites: - type: api - shards: 10 + shards: 20 - type: cli - shards: 3 + shards: 9 release: - version: 11.0.0-rc3 qa-tarball: https://github.com/owncloud/core/releases/download/v11.0.0-rc3/owncloud-complete-20260729-qa.tar.bz2 From b50d147811ee604838aa1d65ff3839c865c0aad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <1005065+DeepDiver1975@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:33:37 +0200 Subject: [PATCH 4/4] fix(acceptance): stop pinning loglevel and mail settings via env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first full-suite run against 11.0.0-rc3 came back with 49 failures out of 5040 scenarios. 40 of them were caused by this workflow, not the image. server.env set OWNCLOUD_LOG_LEVEL and four OWNCLOUD_MAIL_* keys. Those land in overwrite.config.php, which Config::readData() merges after config.php, so they beat anything config:system:set writes. Scenarios that have to *change* one of those settings therefore could not: - apiWebdavUpload1, apiWebdavUpload2 and cliBackground/backgroundQueue set the log level to debug and assert it took effect. All 39 reported "The expected log level is 0 but the log level has been set to 2". - cliProvisioning/resetUserPassword switches mail_smtpmode to sendmail to assert the send fails; with smtp pinned the mail went out and occ exited 0. The mail keys were redundant on top of that: run.sh already sets mail_domain, mail_from_address, mail_smtpmode, mail_smtphost and mail_smtpport itself via occ, and defaults EMAIL_SMTP_PORT to inbucket's 2500. Dropping both groups lets the suite own the settings it needs to mutate. This is the same overwrite.config.php precedence trap the file already documents for the database and redis keys - those must be set via env, these must not. Co-Authored-By: Claude Opus 5 Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com> --- .github/workflows/acceptance.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index abf6afb..16153b8 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -279,11 +279,17 @@ jobs: OWNCLOUD_SHARING_FEDERATION_ALLOW_HTTP_FALLBACK=true OWNCLOUD_INTEGRITY_IGNORE_MISSING_APP_SIGNATURE=testing OWNCLOUD_FILES_EXTERNAL_ALLOW_NEW_LOCAL=true - OWNCLOUD_LOG_LEVEL=2 - OWNCLOUD_MAIL_SMTP_MODE=smtp - OWNCLOUD_MAIL_SMTP_HOST=127.0.0.1 - OWNCLOUD_MAIL_SMTP_PORT=2500 - OWNCLOUD_MAIL_DOMAIN=foobar.com + # Deliberately no OWNCLOUD_LOG_LEVEL and no OWNCLOUD_MAIL_* here. + # run.sh sets mail_domain, mail_from_address, mail_smtpmode, + # mail_smtphost and mail_smtpport itself via occ (and defaults + # EMAIL_SMTP_PORT to inbucket's 2500), so these were redundant - and + # actively harmful: anything in overwrite.config.php wins over + # config:system:set, so a scenario that has to *change* one of these + # settings cannot. Setting them cost 40 scenarios: + # - 39 in apiWebdavUpload1/2 and cliBackground/backgroundQueue, which + # set the log level to debug and assert it took effect + # - 1 in cliProvisioning/resetUserPassword, which switches smtpmode + # to sendmail to assert the send fails EOF # The default schedule runs occ system:cron every minute, which races