Skip to content

[tests-only][full-ci] test: retry copy operation on 500 status code #1017

[tests-only][full-ci] test: retry copy operation on 500 status code

[tests-only][full-ci] test: retry copy operation on 500 status code #1017

Workflow file for this run

name: Acceptance Tests K8S
on:
pull_request:
workflow_dispatch:
schedule:
- cron: "0 1 * * *"
env:
PHP_VERSION: "8.4"
K3D_VERSION: "v5.8.3"
HELM_VERSION: "v3.18.4"
TEST_SERVER_URL: https://ocis-server
STORAGE_DRIVER: ocis
OCIS_WRAPPER_URL: http://localhost:5200
K8S: true
jobs:
api-tests:
name: ${{ matrix.suite }}-k8s
runs-on: ubuntu-26.04
timeout-minutes: 120
if: >-
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
contains(github.event.pull_request.title || '', 'k8s'))
strategy:
fail-fast: false
matrix:
include:
- suite: apiContract
- suite: apiLocks
- suite: apiSettings
- suite: apiNotification
- suite: apiCors
- suite: apiGraphUser
- suite: apiGraph
- suite: apiGraphGroup
# - suite: apiSpaces
- suite: apiSpacesShares
- suite: apiSpacesDavOperation
- suite: apiDownloads
- suite: apiAsyncUpload
- suite: apiDepthInfinity
- suite: apiArchiver
- suite: apiActivities
- suite: apiSearch1
- suite: apiSearch2
# - suite: apiSearchContent
- suite: apiSharingNgShares
- suite: apiReshare
- suite: apiSharingNgPermissions
- suite: apiSharingNgAdditionalShareRole
- suite: apiSharingNgDriveInvitation
# - suite: apiSharingNgItemInvitation
- suite: apiSharingNgDriveLinkShare
- suite: apiSharingNgItemLinkShare
- suite: apiSharingNgLinkShareManagement
- suite: apiAuthApp
# - suite: apiAntivirus
- suite: apiOcm
# - suite: apiCollaboration
- suite: apiVault
- suite: "coreApiAuth,coreApiCapabilities,coreApiFavorites,coreApiMain,coreApiVersions"
- suite: "coreApiShareManagementBasicToShares,coreApiShareManagementToShares"
- suite: "coreApiSharees"
- suite: "coreApiSharePublicLink2"
- suite: "coreApiShareOperationsToShares1,coreApiShareOperationsToShares2,coreApiSharePublicLink1,coreApiShareCreateSpecialToShares1,coreApiShareCreateSpecialToShares2,coreApiShareUpdateToShares"
- suite: "coreApiTrashbin,coreApiTrashbinRestore,coreApiWebdavEtagPropagation1,coreApiWebdavEtagPropagation2"
- suite: "coreApiWebdavDelete,coreApiWebdavOperations,coreApiWebdavMove2"
- suite: "coreApiWebdavProperties"
# - suite: "coreApiWebdavPreviews"
- suite: "coreApiWebdavMove1,coreApiWebdavUpload,coreApiWebdavUploadTUS"
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup PHP ${{ env.PHP_VERSION }}
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2.37.0
with:
php-version: ${{ env.PHP_VERSION }}
extensions: curl, xml, mbstring, zip, ldap, gd
tools: composer
- name: Download k3d
run: |
curl -L \
-o k3d \
https://github.com/k3d-io/k3d/releases/download/${{ env.K3D_VERSION }}/k3d-linux-amd64
echo "dbaa79a76ace7f4ca230a1ff41dc7d8a5036a8ad0309e9c54f9bf3836dbe853e k3d" | sha256sum --check
chmod +x k3d
sudo mv k3d /usr/local/bin/
k3d version
- name: Install Helm
run: |
curl -fsSL -o helm-${{ env.HELM_VERSION }}-linux-amd64.tar.gz https://get.helm.sh/helm-${{ env.HELM_VERSION }}-linux-amd64.tar.gz
tar -zxvf helm-${{ env.HELM_VERSION }}-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
helm version --short
- name: Prepare hosts
run: |
echo "127.0.0.1 ocis-server clamav email collabora onlyoffice fakeoffice tika federation-ocis-server keycloak" \
| sudo tee -a /etc/hosts
- name: Spin up K3d Cluster
run: make -C tests/config/k8s create-cluster
- name: Prepare Helm Charts
env:
ENABLE_ANTIVIRUS: ${{ matrix.suite == 'apiAntivirus' }}
ENABLE_EMAIL: ${{ matrix.suite == 'apiNotification' || matrix.suite == 'apiSettings' || matrix.suite == 'apiOcm' }}
ENABLE_TIKA: ${{ matrix.suite == 'apiSearchContent' || matrix.suite == 'apiVault' }}
ENABLE_WOPI: ${{ matrix.suite == 'apiCollaboration' }}
ENABLE_OCM: ${{ matrix.suite == 'apiOcm' }}
ENABLE_AUTH_APP: ${{ matrix.suite == 'apiAuthApp' }}
ENABLE_VAULT: ${{ matrix.suite == 'apiVault' }}
run: |
cd tests/config/k8s
make prepare-charts
if [[ "${{ matrix.suite }}" == "apiOcm" ]]; then
OCM=true make prepare-charts
fi
# Keycloak/postgres (and the other suite-specific backends) must be up and
# exposed to the cluster before oCIS is deployed: the proxy validates the
# OCIS_OIDC_ISSUER well-known endpoint against Keycloak at startup in vault mode,
# so `helm install --wait` would time out waiting for the proxy pod otherwise.
- name: Deploy Suite-Specific External Backends
run: |
if [[ "${{ matrix.suite }}" == "apiNotification" || \
"${{ matrix.suite }}" == "apiSettings" || \
"${{ matrix.suite }}" == "apiOcm" ]]; then
docker run -d \
-p 1025:1025 \
-p 8025:8025 \
--name mailpit \
axllent/mailpit:v1.22.3
bash tests/config/k8s/expose-external-svc.sh email:1025
fi
if [[ "${{ matrix.suite }}" == "apiAntivirus" ]]; then
docker run -d \
-p 3310:3310 \
--name clamav \
owncloudci/clamavd
bash tests/config/k8s/expose-external-svc.sh clamav:3310
fi
if [[ "${{ matrix.suite }}" == "apiSearchContent" || "${{ matrix.suite }}" == "apiVault" ]]; then
docker run -d \
-p 9998:9998 \
--name tika \
apache/tika:3.2.2.0-full
bash tests/config/k8s/expose-external-svc.sh tika:9998
fi
if [[ "${{ matrix.suite }}" == "apiVault" ]]; then
# GitHub runners ship PostgreSQL pre-installed on 5432, but not always
# already running - reuse it for keycloak's DB instead of running our
# own container for it, once it's up.
sudo systemctl start postgresql
for i in {1..30}; do
sudo -u postgres pg_isready && break
echo "Waiting for postgres... ($i/30)"
sleep 2
done
sudo -u postgres psql -c "CREATE USER keycloak WITH PASSWORD 'keycloak';"
sudo -u postgres psql -c "CREATE DATABASE keycloak OWNER keycloak;"
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 777 keycloak-certs/*
# patch the realm so the "web" client's redirect/origin URLs match
# the k8s ingress domain instead of the non-k8s "localhost:9200" one
sed 's|https://localhost:9200|https://ocis-server|g' \
tests/config/ci/ocis-mfa-ci-realm.dist.json > /tmp/ocis-realm.json
docker run -d --name keycloak --network host \
-e OCIS_DOMAIN=https://ocis-server \
-e KC_HOSTNAME=keycloak \
-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-mfa-ci-realm.dist.json:ro \
quay.io/keycloak/keycloak:26.5.6 \
start-dev --proxy-headers xforwarded \
--spi-connections-http-client-default-disable-trust-manager=true \
--import-realm --health-enabled=true
for i in {1..60}; do
curl -skf https://localhost:9000/health/ready && break
echo "Waiting for keycloak... ($i/60)"
sleep 5
done
bash tests/config/k8s/expose-external-svc.sh keycloak:8443
fi
- name: Deploy oCIS
run: |
cd tests/config/k8s
kubectl get pods -n ocis-server -Aw &
make deploy-ocis
if [[ "${{ matrix.suite }}" == "apiOcm" ]]; then
OCM=true make deploy-ocis
fi
- name: Wait for oCIS to be ready
env:
FILE_URL: ${{ env.TEST_SERVER_URL }}/remote.php/dav/files/admin/hello1.txt
run: |
kubectl wait \
--namespace ocis-server \
--for=condition=Available \
deployment \
--all \
--timeout=10m
kubectl wait \
--namespace ocis-server \
--for=condition=Ready \
pod \
--all \
--timeout=10m
kubectl get pods -n ocis-server
retry() {
local label=$1
shift
for i in {1..30}; do
if "$@"; then
echo "$label succeeded"
return 0
fi
echo "$label attempt $i failed, retrying in 10s..."
sleep 10
done
echo "$label failed after 30 attempts"
return 1
}
if [[ "${{ matrix.suite }}" == "apiVault" ]]; then
# In vault mode IDM_CREATE_DEMO_USERS=false, so there is no "admin"
# LDAP user to authenticate the basic-auth check below against.
# Poll the proxy's unauthenticated debug readyz endpoint instead,
# reached via port-forward since it isn't exposed by any Service.
# local port 19205 (not 9205): 9100-9399 is already bound on the
# host by the k3d loadbalancer's NodePort range, see create-cluster.
kubectl -n ocis-server port-forward deployment/proxy 19205:9205 &
PORT_FORWARD_PID=$!
trap 'kill $PORT_FORWARD_PID 2>/dev/null' EXIT
proxy_ready() {
curl -sf http://localhost:19205/readyz > /dev/null
}
retry "proxy readyz" proxy_ready || exit 1
else
echo "Creating test file in oCIS..."
request() {
local method=$1
shift
curl -ks -o /dev/null -w "%{http_code}" \
-X "$method" \
-u admin:admin \
"$@" \
"$FILE_URL"
}
put_file() {
request PUT \
-H "Content-Type: text/plain" \
--data "Hello from GitHub Actions!"
}
delete_file() {
request DELETE
}
check_status() {
local expected=$1
shift
status=$("$@")
[ "$status" = "$expected" ]
}
echo "Creating test file..."
retry "create file (HTTP 201)" check_status 201 put_file || exit 1
echo "Deleting test file..."
retry "delete file (HTTP 204)" check_status 204 delete_file || exit 1
fi
- name: Expose debug ports
run: bash tests/config/k8s/expose-debug-svc.sh
# unauthenticated /readyz endpoint after config-triggered restarts. Port 9205 is unavailable
# on the runner (k3d reserves 9100-9399), so expose it on 19205 for the rest of the job.
# Keep the forward running since env-config scenarios may restart oCIS. The reconnect loop
# recreates it after proxy pod restarts, unlike a one-off port-forward tied to a specific pod.
- name: Expose proxy readyz
if: matrix.suite == 'apiVault'
run: |
(
while true; do
kubectl -n ocis-server port-forward deployment/proxy 19205:9205 >> /tmp/proxy-readyz-portforward.log 2>&1
sleep 1
done
) &
- name: Build ociswrapper
run: make -C tests/ociswrapper/
- name: Start ociswrapper
run: |
tests/ociswrapper/bin/ociswrapper serve \
--url ${{ env.TEST_SERVER_URL }} \
--admin-username admin \
--admin-password admin \
--skip-ocis-run \
-n ocis-server &
- name: Prepare expected failures
if: startsWith( matrix.suite, 'core' )
env:
EXPECTED_FAILURES_FILE: tests/acceptance/expected-failures-API-on-OCIS-storage.md
WITH_REMOTE_PHP: "false"
run: |
if [[ "$WITH_REMOTE_PHP" != "true" ]]; then
cat tests/acceptance/expected-failures-without-remotephp.md >> \
"$EXPECTED_FAILURES_FILE"
fi
- name: Run API ${{ matrix.suite }} tests
if: startsWith( matrix.suite, 'api' )
env:
TEST_SERVER_URL: ${{ env.TEST_SERVER_URL }}
TEST_SERVER_FED_URL: https://federation-ocis-server
STORAGE_DRIVER: ${{ env.STORAGE_DRIVER }}
BEHAT_SUITES: ${{ matrix.suite }}
BEHAT_FILTER_TAGS: "~@skip&&~@skipOnGraph&&~@skipOnOcis-OCIS-Storage"
EXPECTED_FAILURES_FILE: tests/acceptance/expected-failures-localAPI-on-OCIS-storage.md
OCIS_WRAPPER_URL: ${{ env.OCIS_WRAPPER_URL }}
COLLABORATION_SERVICE_URL: http://ocis-server:9304
K8S: ${{ env.K8S }}
KEYCLOAK: ${{ matrix.suite == 'apiVault' }}
KC_URL: https://keycloak:8443
PROXY_READYZ_URL: ${{ matrix.suite == 'apiVault' && 'http://localhost:19205/readyz' || '' }}
run: make test-acceptance-api
- name: Run Core ${{ matrix.suite }} tests
if: startsWith( matrix.suite, 'core' )
env:
TEST_SERVER_URL: ${{ env.TEST_SERVER_URL }}
OCIS_REVA_DATA_ROOT: ""
STORAGE_DRIVER: ocis
BEHAT_FILTER_TAGS: "~@skip&&~@skipOnGraph&&~@skipOnOcis-OCIS-Storage"
BEHAT_SUITES: ${{ matrix.suite }}
ACCEPTANCE_TEST_TYPE: core-api
EXPECTED_FAILURES_FILE: tests/acceptance/expected-failures-API-on-OCIS-storage.md
UPLOAD_DELETE_WAIT_TIME: "0"
OCIS_WRAPPER_URL: ${{ env.OCIS_WRAPPER_URL }}
WITH_REMOTE_PHP: "false"
K8S: ${{ env.K8S }}
run: make test-acceptance-api