diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4089b81 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +--- +name: CI +on: + push: +jobs: + code-quality: + name: "Code quality checks" + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer ci:install" + - name: "Run command" + run: "composer ci:php:stan" + + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + needs: [ code-quality ] + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer ci:install" + - name: "Run the tests" + run: "composer ci:tests:unit" + + functional-tests: + name: Functional Tests + runs-on: ubuntu-latest + needs: [ code-quality ] + steps: + - name: "Checkout" + uses: actions/checkout@v4 + - name: "Install Composer dependencies" + run: "composer update --no-progress" + - name: "Run the tests" + run: "composer ci:tests:functional" diff --git a/.gitignore b/.gitignore index 485dee6..685efea 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,8 @@ -.idea +.idea/ +.cache +Build/testing-docker/.env +bin/ +public/ +typo3temp/ +vendor/ +composer.lock diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh new file mode 100755 index 0000000..af4723c --- /dev/null +++ b/Build/Scripts/runTests.sh @@ -0,0 +1,1036 @@ +#!/usr/bin/env bash + +# +# TYPO3 core test runner based on docker or podman +# + +waitFor() { + local HOST=${1} + local PORT=${2} + local TESTCOMMAND=" + COUNT=0; + while ! nc -z ${HOST} ${PORT}; do + if [ \"\${COUNT}\" -gt 10 ]; then + echo \"Can not connect to ${HOST} port ${PORT}. Aborting.\"; + exit 1; + fi; + sleep 1; + COUNT=\$((COUNT + 1)); + done; + " + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name wait-for-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_ALPINE} /bin/sh -c "${TESTCOMMAND}" +} + +cleanUp() { + ATTACHED_CONTAINERS=$(${CONTAINER_BIN} ps --filter network=${NETWORK} --format='{{.Names}}') + for ATTACHED_CONTAINER in ${ATTACHED_CONTAINERS}; do + ${CONTAINER_BIN} kill ${ATTACHED_CONTAINER} >/dev/null + done + ${CONTAINER_BIN} network rm ${NETWORK} >/dev/null +} + +handleDbmsOptions() { + # -a, -d, -i depend on each other. Validate input combinations and set defaults. + case ${DBMS} in + mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" + if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + mysql) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="8.0" + if ! [[ ${DBMS_VERSION} =~ ^(8.0|8.1|8.2|8.3)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + postgres) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10" + if ! [[ ${DBMS_VERSION} =~ ^(10|11|12|13|14|15|16)$ ]]; then + echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + sqlite) + if [ -n "${DATABASE_DRIVER}" ]; then + echo "Invalid combination -d ${DBMS} -a ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + if [ -n "${DBMS_VERSION}" ]; then + echo "Invalid combination -d ${DBMS} -i ${DATABASE_DRIVER}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + *) + echo "Invalid option -d ${DBMS}" >&2 + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + ;; + esac +} + +cleanBuildFiles() { + echo -n "Clean builds ... " + rm -rf \ + Build/JavaScript \ + Build/node_modules + echo "done" +} + +cleanCacheFiles() { + echo -n "Clean caches ... " + rm -rf \ + .cache \ + Build/.cache \ + Build/composer/.cache/ \ + .php-cs-fixer.cache + echo "done" +} + +cleanTestFiles() { + # composer distribution test + echo -n "Clean composer distribution test ... " + rm -rf \ + Build/composer/composer.json \ + Build/composer/composer.lock \ + Build/composer/public/index.php \ + Build/composer/public/typo3 \ + Build/composer/public/typo3conf/ext \ + Build/composer/var/ \ + Build/composer/vendor/ + echo "done" + + # test related + echo -n "Clean test related files ... " + rm -rf \ + Build/phpunit/FunctionalTests-Job-*.xml \ + typo3/sysext/core/Tests/AcceptanceTests-Job-* \ + typo3/sysext/core/Tests/Acceptance/Support/_generated \ + typo3temp/var/tests/ + echo "done" +} + +cleanRenderedDocumentationFiles() { + echo -n "Clean rendered documentation files ... " + rm -rf \ + ../../../typo3/sysext/*/Documentation-GENERATED-temp + echo "done" +} + +getPhpImageVersion() { + case ${1} in + 8.2) + echo -n "1.11" + ;; + 8.3) + echo -n "1.12" + ;; + esac +} + +loadHelp() { + # Load help text into $HELP + read -r -d '' HELP < + Specifies the test suite to run + - acceptance: main application acceptance tests + - acceptanceInstall: installation acceptance tests, only with -d mariadb|postgres|sqlite + - buildCss: execute scss to css builder + - buildJavascript: execute typescript to javascript builder + - cgl: test and fix all core php files + - cglGit: test and fix latest committed patch for CGL compliance + - cglHeader: test and fix file header for all core php files + - cglHeaderGit: test and fix latest committed patch for CGL file header compliance + - checkAnnotations: check php code for allowed annotations + - checkBom: check UTF-8 files do not contain BOM + - checkComposer: check composer.json files for version integrity + - checkExceptionCodes: test core for duplicate exception codes + - checkExtensionScannerRst: test all .rst files referenced by extension scanner exist + - checkFilePathLength: test core file paths do not exceed maximum length + - checkGitSubmodule: test core git has no sub modules defined + - checkGruntClean: Verify "grunt build" is clean. Warning: Executes git commands! Usually used in CI only. + - checkIsoDatabase: Verify "updateIsoDatabase.php" does not change anything. + - checkNamespaceIntegrity: Verify namespace integrity in class and test code files are in good shape. + - checkPermissions: test some core files for correct executable bits + - checkRst: test .rst files for integrity + - checkTestClassFinal: check test case classes are final + - checkTestMethodsPrefix: check tests methods do not start with "test" + - clean: clean up build, cache and testing related files and folders + - cleanBuild: clean up build related files and folders + - cleanCache: clean up cache related files and folders + - cleanRenderedDocumentation: clean up rendered documentation files and folders (Documentation-GENERATED-temp) + - cleanTests: clean up test related files and folders + - composer: "composer" command dispatcher, to execute various composer commands + - composerInstall: "composer install" + - composerInstallMax: "composer update", with no platform.php config. + - composerInstallMin: "composer update --prefer-lowest", with platform.php set to PHP version x.x.0. + - composerTestDistribution: "composer update" in Build/composer to verify core dependencies + - composerValidate: "composer validate" + - functional: PHP functional tests + - functionalDeprecated: deprecated PHP functional tests + - lintPhp: PHP linting + - lintScss: SCSS linting + - lintTypescript: TS linting + - lintHtml: HTML linting + - listExceptionCodes: list core exception codes in JSON format + - phpstan: phpstan tests + - phpstanGenerateBaseline: regenerate phpstan baseline, handy after phpstan updates + - unit (default): PHP unit tests + - unitDeprecated: deprecated PHP unit tests + - unitJavascript: JavaScript unit tests + - unitRandom: PHP unit tests in random order, add -o to use specific seed + + -b + Container environment: + - podman (default) + - docker + + -a + Only with -s functional|functionalDeprecated + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + + -d + Only with -s functional|functionalDeprecated|acceptance|acceptanceInstall + Specifies on which DBMS tests are performed + - sqlite: (default): use sqlite + - mariadb: use mariadb + - mysql: use MySQL + - postgres: use postgres + + -i version + Specify a specific database version + With "-d mariadb": + - 10.4 short-term, maintained until 2024-06-18 (default) + - 10.5 short-term, maintained until 2025-06-24 + - 10.6 long-term, maintained until 2026-06 + - 10.7 short-term, no longer maintained + - 10.8 short-term, maintained until 2023-05 + - 10.9 short-term, maintained until 2023-08 + - 10.10 short-term, maintained until 2023-11 + - 10.11 long-term, maintained until 2028-02 + - 11.0 development series + - 11.1 short-term development series + With "-d mysql": + - 8.0 maintained until 2026-04 (default) LTS + - 8.1 unmaintained since 2023-10 + - 8.2 unmaintained since 2024-01 + - 8.3 maintained until 2024-04 + With "-d postgres": + - 10 unmaintained since 2022-11-10 (default) + - 11 unmaintained since 2023-11-09 + - 12 maintained until 2024-11-14 + - 13 maintained until 2025-11-13 + - 14 maintained until 2026-11-12 + - 15 maintained until 2027-11-11 + - 16 maintained until 2028-11-09 + + -c + Only with -s functional|acceptance + Hack functional or acceptance tests into #numberOfChunks pieces and run tests of #chunk. + Example -c 3/13 + + -p <8.2|8.3> + Specifies the PHP minor version to be used + - 8.2 (default): use PHP 8.2 + - 8.3: use PHP 8.3 + + -e "" (DEPRECATED). + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance + Additional options to send to phpunit (unit & functional tests) or codeception (acceptance + tests). For phpunit, options starting with "--" must be added after options starting with "-". + Example -e "-d memory_limit=-1 --filter filterByValueRecursiveCorrectlyFiltersArray" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + + DEPRECATED - pass arguments after the `--` separator directly. For example, instead of + Build/Scripts/runTests.sh -s unit -e "--filter filterByValueRecursiveCorrectlyFiltersArray" + use + Build/Scripts/runTests.sh -s unit -- --filter filterByValueRecursiveCorrectlyFiltersArray + + -g + Only with -s acceptance|acceptanceInstall + Activate selenium grid as local port to watch browser clicking around. Can be surfed using + http://localhost:7900/. A browser tab is opened automatically if xdg-open is installed. + + -x + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance|acceptanceInstall + Send information to host instance for test or system under test break points. This is especially + useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port + can be selected with -y + + -y + Send xdebug information to a different port than default 9003 if an IDE like PhpStorm + is not listening on default port. + + -o + Only with -s unitRandom + Set specific random seed to replay a random run in this order again. The phpunit randomizer + outputs the used seed at the end (in gitlab core testing logs, too). Use that number to + replay the unit tests in that order. + + -n + Only with -s cgl|cglGit|cglHeader|cglHeaderGit + Activate dry-run in CGL check that does not actively change files and only prints broken ones. + + -u + Update existing typo3/core-testing-* container images and remove obsolete dangling image versions. + Use this if weird test errors occur. + + -h + Show this help. + +Examples: + # Run all core unit tests using PHP 8.2 + ./Build/Scripts/runTests.sh + ./Build/Scripts/runTests.sh -s unit + + # Run all core units tests and enable xdebug (have a PhpStorm listening on port 9003!) + ./Build/Scripts/runTests.sh -x + + # Run unit tests in phpunit with xdebug on PHP 8.3 and filter for test filterByValueRecursiveCorrectlyFiltersArray + ./Build/Scripts/runTests.sh -x -p 8.3 -- --filter filterByValueRecursiveCorrectlyFiltersArray + + # Run functional tests in phpunit with a filtered test method name in a specified file + # example will currently execute two tests, both of which start with the search term + ./Build/Scripts/runTests.sh -s functional -- \ + --filter datetimeInstanceCanBePersistedToDatabaseIfTypeIsExplicitlySpecified \ + typo3/sysext/core/Tests/Functional/Database/ConnectionTest.php + + # Run functional tests on postgres with xdebug, php 8.3 and execute a restricted set of tests + ./Build/Scripts/runTests.sh -x -p 8.3 -s functional -d postgres typo3/sysext/core/Tests/Functional/Authentication + + # Run functional tests on postgres 11 + ./Build/Scripts/runTests.sh -s functional -d postgres -i 11 + + # Run restricted set of application acceptance tests + ./Build/Scripts/runTests.sh -s acceptance typo3/sysext/core/Tests/Acceptance/Application/Login/BackendLoginCest.php:loginButtonMouseOver + + # Run installer tests of a new instance on sqlite + ./Build/Scripts/runTests.sh -s acceptanceInstall -d sqlite + + # Run composer require to require a dependency + ./Build/Scripts/runTests.sh -s composer -- require --dev typo3/testing-framework:dev-main + + # Some composer command examples + ./Build/Scripts/runTests.sh -s composer -- dumpautoload + ./Build/Scripts/runTests.sh -s composer -- info | grep "symfony" +EOF +} + +# Test if docker exists, else exit out with error +if ! type "docker" >/dev/null 2>&1 && ! type "podman" >/dev/null 2>&1; then + echo "This script relies on docker or podman. Please install" >&2 + exit 1 +fi + +# Go to the directory this script is located, so everything else is relative +# to this dir, no matter from where this script is called, then go up two dirs. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 +cd ../../ || exit 1 +CORE_ROOT="${PWD}" + +# Default variables +TEST_SUITE="unit" +DBMS="sqlite" +DBMS_VERSION="" +PHP_VERSION="8.2" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +ACCEPTANCE_HEADLESS=1 +EXTRA_TEST_OPTIONS="" +PHPUNIT_RANDOM="" +CGLCHECK_DRY_RUN="" +DATABASE_DRIVER="" +CHUNKS=0 +THISCHUNK=0 +CONTAINER_BIN="" +COMPOSER_ROOT_VERSION="13.1.x-dev" +PHPSTAN_CONFIG_FILE="phpstan.local.neon" +CONTAINER_INTERACTIVE="-it --init" +HOST_UID=$(id -u) +HOST_PID=$(id -g) +USERSET="" +SUFFIX=$(echo $RANDOM) +NETWORK="typo3-core-${SUFFIX}" +CI_PARAMS="" +CONTAINER_HOST="host.docker.internal" + +# Option parsing updates above default vars +# Reset in case getopts has been used previously in the shell +OPTIND=1 +# Array for invalid options +INVALID_OPTIONS=() +# Simple option parsing based on getopts (! not getopt) +while getopts ":a:b:s:c:d:i:p:e:xy:o:nhug" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + b) + if ! [[ ${OPTARG} =~ ^(docker|podman)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + CONTAINER_BIN=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; + c) + if ! [[ ${OPTARG} =~ ^([0-9]+\/[0-9]+)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + else + # Split "2/13" - run chunk 2 of 13 chunks + THISCHUNK=$(echo "${OPTARG}" | cut -d '/' -f1) + CHUNKS=$(echo "${OPTARG}" | cut -d '/' -f2) + fi + ;; + d) + DBMS=${OPTARG} + ;; + i) + DBMS_VERSION=${OPTARG} + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(8.2|8.3)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + g) + ACCEPTANCE_HEADLESS=0 + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + o) + PHPUNIT_RANDOM="--random-order-seed=${OPTARG}" + ;; + n) + CGLCHECK_DRY_RUN="-n" + ;; + h) + loadHelp + echo "${HELP}" + exit 0 + ;; + u) + TEST_SUITE=update + ;; + \?) + INVALID_OPTIONS+=("${OPTARG}") + ;; + :) + INVALID_OPTIONS+=("${OPTARG}") + ;; + esac +done + +# Exit on invalid options +if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then + echo "Invalid option(s):" >&2 + for I in "${INVALID_OPTIONS[@]}"; do + echo "-"${I} >&2 + done + echo >&2 + echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 + exit 1 +fi + +handleDbmsOptions + +# ENV var "CI" is set by gitlab-ci. Use it to force some CI details. +if [ "${CI}" == "true" ]; then + PHPSTAN_CONFIG_FILE="phpstan.ci.neon" + CONTAINER_INTERACTIVE="" + CI_PARAMS="--pull=never" +fi + +# determine default container binary to use: 1. podman 2. docker +if [[ -z "${CONTAINER_BIN}" ]]; then + if type "podman" >/dev/null 2>&1; then + CONTAINER_BIN="podman" + elif type "docker" >/dev/null 2>&1; then + CONTAINER_BIN="docker" + fi +fi + +if [ $(uname) != "Darwin" ] && [ ${CONTAINER_BIN} = "docker" ]; then + # Run docker jobs as current user to prevent permission issues. Not needed with podman. + USERSET="--user $HOST_UID" +fi + +if ! type ${CONTAINER_BIN} >/dev/null 2>&1; then + echo "Selected container environment \"${CONTAINER_BIN}\" not found. Please install or use -b option to select one." >&2 + exit 1 +fi + +IMAGE_APACHE="ghcr.io/typo3/core-testing-apache24:1.3" +IMAGE_PHP="ghcr.io/typo3/core-testing-$(echo "php${PHP_VERSION}" | sed -e 's/\.//'):$(getPhpImageVersion $PHP_VERSION)" + +IMAGE_NODEJS="ghcr.io/typo3/core-testing-nodejs18:1.2" +IMAGE_NODEJS_CHROME="ghcr.io/typo3/core-testing-nodejs18-chrome:1.2" +IMAGE_ALPINE="docker.io/alpine:3.8" +IMAGE_SELENIUM="docker.io/selenium/standalone-chrome:4.11.0-20230801" +IMAGE_REDIS="docker.io/redis:4-alpine" +IMAGE_MEMCACHED="docker.io/memcached:1.5-alpine" +IMAGE_MARIADB="docker.io/mariadb:${DBMS_VERSION}" +IMAGE_MYSQL="docker.io/mysql:${DBMS_VERSION}" +IMAGE_POSTGRES="docker.io/postgres:${DBMS_VERSION}-alpine" + +# Detect arm64 to use seleniarm image. +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + IMAGE_SELENIUM="docker.io/seleniarm/standalone-chromium:4.10.0-20230615" +fi + +# Remove handled options and leaving the rest in the line, so it can be passed raw to commands +shift $((OPTIND - 1)) + +# Create .cache dir: composer and various npm jobs need this. +mkdir -p .cache +mkdir -p typo3temp/var/tests + +${CONTAINER_BIN} network create ${NETWORK} >/dev/null + +if [ ${CONTAINER_BIN} = "docker" ]; then + # docker needs the add-host for xdebug remote debugging. podman has host.container.internal built in + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} --rm --network ${NETWORK} --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +else + # podman + CONTAINER_HOST="host.containers.internal" + CONTAINER_COMMON_PARAMS="${CONTAINER_INTERACTIVE} ${CI_PARAMS} --rm --network ${NETWORK} -v ${CORE_ROOT}:${CORE_ROOT} -w ${CORE_ROOT}" +fi + +if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE="-e XDEBUG_MODE=off" + XDEBUG_CONFIG=" " + PHP_FPM_OPTIONS="-d xdebug.mode=off" +else + XDEBUG_MODE="-e XDEBUG_MODE=debug -e XDEBUG_TRIGGER=foo" + XDEBUG_CONFIG="client_port=${PHP_XDEBUG_PORT} client_host=${CONTAINER_HOST}" + PHP_FPM_OPTIONS="-d xdebug.mode=debug -d xdebug.start_with_request=yes -d xdebug.client_host=${CONTAINER_HOST} -d xdebug.client_port=${PHP_XDEBUG_PORT} -d memory_limit=256M" +fi + +# Suite execution +case ${TEST_SUITE} in + acceptance) + CODECEPION_ENV="--env ci" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,headless" + fi + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitAcceptanceTests.php -v ${CHUNKS} + COMMAND=(bin/codecept run Application -d -g AcceptanceTests-Job-${THISCHUNK} -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + else + COMMAND=(bin/codecept run Application -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} "$@" --html reports.html) + fi + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + waitFor chrome 7900 + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mariadb-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabasePassword=funcp -e typo3DatabaseHost=mysql-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=func_test -e typo3DatabaseUsername=funcu -e typo3DatabasePassword=funcp -e typo3DatabaseHost=postgres-ac-${SUFFIX}" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + acceptanceInstall) + SELENIUM_GRID="" + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ]; then + SELENIUM_GRID="-p 7900:7900 -e SE_VNC_NO_PASSWORD=1 -e VNC_NO_PASSWORD=1" + fi + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance" "${CORE_ROOT}/typo3temp/var/tests/AcceptanceReports" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance" + APACHE_OPTIONS="-e APACHE_RUN_USER=#${HOST_UID} -e APACHE_RUN_SERVERNAME=web -e APACHE_RUN_GROUP=#${HOST_PID} -e APACHE_RUN_DOCROOT=${CORE_ROOT}/typo3temp/var/tests/acceptance -e PHPFPM_HOST=phpfpm -e PHPFPM_PORT=9000" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d ${SELENIUM_GRID} --name ac-istall-chrome-${SUFFIX} --network ${NETWORK} --network-alias chrome --tmpfs /dev/shm:rw,nosuid,nodev,noexec ${IMAGE_SELENIUM} >/dev/null + if [ ${CONTAINER_BIN} = "docker" ]; then + ${CONTAINER_BIN} run --rm -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm --add-host "${CONTAINER_HOST}:host-gateway" ${USERSET} -e PHPFPM_USER=${HOST_UID} -e PHPFPM_GROUP=${HOST_PID} -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web --add-host "${CONTAINER_HOST}:host-gateway" -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + else + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-phpfpm-${SUFFIX} --network ${NETWORK} --network-alias phpfpm ${USERSET} -e PHPFPM_USER=0 -e PHPFPM_GROUP=0 -v ${CORE_ROOT}:${CORE_ROOT} ${IMAGE_PHP} php-fpm -R ${PHP_FPM_OPTIONS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} -d --name ac-install-web-${SUFFIX} --network ${NETWORK} --network-alias web -v ${CORE_ROOT}:${CORE_ROOT} ${APACHE_OPTIONS} ${IMAGE_APACHE} >/dev/null + fi + waitFor chrome 4444 + waitFor chrome 7900 + waitFor web 80 + if [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "xdg-open" >/dev/null; then + xdg-open http://localhost:7900/?autoconnect=1 >/dev/null + elif [ "${ACCEPTANCE_HEADLESS}" -eq 0 ] && type "open" >/dev/null; then + open http://localhost:7900/?autoconnect=1 >/dev/null + fi + case ${DBMS} in + mariadb) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mariadb-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mariadb ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + mysql) + CODECEPION_ENV="--env ci,mysql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,mysql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-ac-install-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-ac-install-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3InstallMysqlDatabaseName=func_test -e typo3InstallMysqlDatabaseUsername=root -e typo3InstallMysqlDatabasePassword=funcp -e typo3InstallMysqlDatabaseHost=mysql-ac-install-${SUFFIX}" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-mysql ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + postgres) + CODECEPION_ENV="--env ci,postgresql" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,postgresql,headless" + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-ac-install-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-ac-install-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3InstallPostgresqlDatabasePort=5432 -e typo3InstallPostgresqlDatabaseName=${USER} -e typo3InstallPostgresqlDatabaseHost=postgres-ac-install-${SUFFIX} -e typo3InstallPostgresqlDatabaseUsername=funcu -e typo3InstallPostgresqlDatabasePassword=funcp" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-postgres ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + sqlite) + rm -rf "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/acceptance-sqlite-dbs/" + CODECEPION_ENV="--env ci,sqlite" + if [ "${ACCEPTANCE_HEADLESS}" -eq 1 ]; then + CODECEPION_ENV="--env ci,sqlite,headless" + fi + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite" + COMMAND="bin/codecept run Install -d -c typo3/sysext/core/Tests/codeception.yml ${EXTRA_TEST_OPTIONS} ${CODECEPION_ENV} --html reports.html" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name ac-install-sqlite ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + esac + ;; + buildCss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt css" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + buildJavascript) + COMMAND="cd Build/; npm ci || exit 1; node_modules/grunt/bin/grunt scripts" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name build-js-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + cgl) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/config.php typo3/" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommit.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + cglHeader) + # Active dry-run for cgl needs not "-n" but specific options + if [ -n "${CGLCHECK_DRY_RUN}" ]; then + CGLCHECK_DRY_RUN="--dry-run --diff" + fi + COMMAND="php -dxdebug.mode=off bin/php-cs-fixer fix -v ${CGLCHECK_DRY_RUN} --path-mode intersection --config=Build/php-cs-fixer/header-comment.php typo3/" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-${SUFFIX} ${IMAGE_PHP} ${COMMAND} + SUITE_EXIT_CODE=$? + ;; + cglHeaderGit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name cgl-header-git-${SUFFIX} ${IMAGE_PHP} Build/Scripts/cglFixMyCommitFileHeader.sh ${CGLCHECK_DRY_RUN} + SUITE_EXIT_CODE=$? + ;; + checkAnnotations) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-annotations-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/annotationChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestClassFinal) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-classes-final-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testClassFinalChecker.php + SUITE_EXIT_CODE=$? + ;; + checkTestMethodsPrefix) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-test-methods-prefix-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/testMethodPrefixChecker.php + SUITE_EXIT_CODE=$? + ;; + checkBom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-utf8bom-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkUtf8Bom.sh + SUITE_EXIT_CODE=$? + ;; + checkComposer) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-composer-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkIntegrityComposer.php + SUITE_EXIT_CODE=$? + ;; + checkExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh + SUITE_EXIT_CODE=$? + ;; + checkExtensionScannerRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-extensionscanner-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/extensionScannerRstFileReferences.php + SUITE_EXIT_CODE=$? + ;; + checkFilePathLength) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-file-path-length-${SUFFIX} ${IMAGE_PHP} Build/Scripts/maxFilePathLength.sh + SUITE_EXIT_CODE=$? + ;; + checkGitSubmodule) + COMMAND="if [ \$(git submodule status 2>&1 | wc -l) -ne 0 ]; then echo \"Found a submodule definition in repository\"; exit 1; fi" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-git-submodule-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkGruntClean) + COMMAND="find 'typo3/sysext' -name '*.js' -not -path '*/Fixtures/*' -exec rm '{}' + && cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt build; cd ..; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-grunt-clean-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkIsoDatabase) + COMMAND="git checkout -- composer.json; git checkout -- composer.lock; php -dxdebug.mode=off Build/Scripts/updateIsoDatabase.php; git add *; git status; git status | grep -q \"nothing to commit, working tree clean\"" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-iso-database-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + checkNamespaceIntegrity) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-namespaces-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/checkNamespaceIntegrity.php + SUITE_EXIT_CODE=$? + ;; + checkPermissions) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-permissions-${SUFFIX} ${IMAGE_PHP} Build/Scripts/checkFilePermissions.sh + SUITE_EXIT_CODE=$? + ;; + checkRst) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name check-rst-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/validateRstFiles.php + SUITE_EXIT_CODE=$? + ;; + clean) + cleanBuildFiles + cleanCacheFiles + cleanRenderedDocumentationFiles + cleanTestFiles + ;; + cleanBuild) + cleanBuildFiles + ;; + cleanCache) + cleanCacheFiles + ;; + cleanRenderedDocumentation) + cleanRenderedDocumentationFiles + ;; + cleanTests) + cleanTestFiles + ;; + composer) + COMMAND=(composer "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + composerInstall) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} composer install --no-progress --no-interaction + SUITE_EXIT_CODE=$? + ;; + composerInstallMax) + COMMAND="composer config --unset platform.php; composer update --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-max-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerInstallMin) + COMMAND="composer config platform.php ${PHP_VERSION}.0; composer update --prefer-lowest --no-progress --no-interaction; composer dumpautoload" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-install-min-${SUFFIX} -e COMPOSER_CACHE_DIR=.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerTestDistribution) + COMMAND="cd Build/composer; rm -rf composer.json composer.lock public/index.php public/typo3 public/typo3conf/ext var/ vendor/; cp composer.dist.json composer.json; composer update --no-progress --no-interaction" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-test-distribution-${SUFFIX} -e COMPOSER_CACHE_DIR=${CORE_ROOT}/.cache/composer -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + composerValidate) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name composer-validate-${SUFFIX} ${IMAGE_PHP} composer validate + SUITE_EXIT_CODE=$? + ;; + functional) + if [ "${CHUNKS}" -gt 0 ]; then + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name func-splitter-${SUFFIX} ${IMAGE_PHP} php -dxdebug.mode=off Build/Scripts/splitFunctionalTests.php -v ${CHUNKS} + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests-Job-${THISCHUNK}.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + else + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTests.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + fi + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-${SUFFIX} 6379 + waitFor memcached-func-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + functionalDeprecated) + COMMAND=(bin/phpunit -c Build/phpunit/FunctionalTestsDeprecated.xml --exclude-group not-${DBMS} ${EXTRA_TEST_OPTIONS} "$@") + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name redis-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_REDIS} >/dev/null + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name memcached-func-dep-${SUFFIX} --network ${NETWORK} -d ${IMAGE_MEMCACHED} >/dev/null + waitFor redis-func-dep-${SUFFIX} 6379 + waitFor memcached-func-dep-${SUFFIX} 11211 + CONTAINER_COMMON_PARAMS="${CONTAINER_COMMON_PARAMS} -e typo3TestingRedisHost=redis-func-dep-${SUFFIX} -e typo3TestingMemcachedHost=memcached-func-dep-${SUFFIX}" + case ${DBMS} in + mariadb) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mariadb-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MARIADB} >/dev/null + waitFor mariadb-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mariadb-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + mysql) + echo "Using driver: ${DATABASE_DRIVER}" + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name mysql-func-dep-${SUFFIX} --network ${NETWORK} -d -e MYSQL_ROOT_PASSWORD=funcp --tmpfs /var/lib/mysql/:rw,noexec,nosuid ${IMAGE_MYSQL} >/dev/null + waitFor mysql-func-dep-${SUFFIX} 3306 + CONTAINERPARAMS="-e typo3DatabaseDriver=${DATABASE_DRIVER} -e typo3DatabaseName=func_test -e typo3DatabaseUsername=root -e typo3DatabaseHost=mysql-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + postgres) + ${CONTAINER_BIN} run --rm ${CI_PARAMS} --name postgres-func-dep-${SUFFIX} --network ${NETWORK} -d -e POSTGRES_PASSWORD=funcp -e POSTGRES_USER=funcu --tmpfs /var/lib/postgresql/data:rw,noexec,nosuid ${IMAGE_POSTGRES} >/dev/null + waitFor postgres-func-dep-${SUFFIX} 5432 + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_pgsql -e typo3DatabaseName=bamboo -e typo3DatabaseUsername=funcu -e typo3DatabaseHost=postgres-func-dep-${SUFFIX} -e typo3DatabasePassword=funcp" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + sqlite) + # create sqlite tmpfs mount typo3temp/var/tests/functional-sqlite-dbs/ to avoid permission issues + mkdir -p "${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/" + CONTAINERPARAMS="-e typo3DatabaseDriver=pdo_sqlite --tmpfs ${CORE_ROOT}/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name functional-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${CONTAINERPARAMS} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + esac + ;; + lintPhp) + COMMAND="php -v | grep '^PHP'; find typo3/ -name \\*.php -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-php-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintScss) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt stylelint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-css-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintTypescript) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt eslint" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-typescript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + lintHtml) + COMMAND="cd Build; npm ci || exit 1; node_modules/grunt/bin/grunt exec:lintspaces" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name lint-html-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + listExceptionCodes) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name list-exception-codes-${SUFFIX} ${IMAGE_PHP} Build/Scripts/duplicateExceptionCodeCheck.sh -p + SUITE_EXIT_CODE=$? + ;; + phpstan) + COMMAND=(php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G "$@") + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-${SUFFIX} ${IMAGE_PHP} "${COMMAND[@]}" + SUITE_EXIT_CODE=$? + ;; + phpstanGenerateBaseline) + COMMAND="php -dxdebug.mode=off bin/phpstan analyse -c Build/phpstan/${PHPSTAN_CONFIG_FILE} --no-progress --no-interaction --memory-limit 4G --generate-baseline=Build/phpstan/phpstan-baseline.neon" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name phpstan-baseline-${SUFFIX} ${IMAGE_PHP} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unit) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitDeprecated) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-deprecated-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTestsDeprecated.xml ${EXTRA_TEST_OPTIONS} "$@" + SUITE_EXIT_CODE=$? + ;; + unitJavascript) + COMMAND="cd Build; npm ci || exit 1; CHROME_SANDBOX=false BROWSERS=chrome npm run test" + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-javascript-${SUFFIX} -e HOME=${CORE_ROOT}/.cache ${IMAGE_NODEJS_CHROME} /bin/sh -c "${COMMAND}" + SUITE_EXIT_CODE=$? + ;; + unitRandom) + ${CONTAINER_BIN} run ${CONTAINER_COMMON_PARAMS} --name unit-random-${SUFFIX} ${XDEBUG_MODE} -e XDEBUG_CONFIG="${XDEBUG_CONFIG}" ${IMAGE_PHP} bin/phpunit -c Build/phpunit/UnitTests.xml --order-by=random ${EXTRA_TEST_OPTIONS} ${PHPUNIT_RANDOM} "$@" + SUITE_EXIT_CODE=$? + ;; + update) + # pull typo3/core-testing-* versions of those ones that exist locally + echo "> pull ghcr.io/typo3/core-testing-* versions of those ones that exist locally" + ${CONTAINER_BIN} images "ghcr.io/typo3/core-testing-*" --format "{{.Repository}}:{{.Tag}}" | xargs -I {} ${CONTAINER_BIN} pull {} + echo "" + # remove "dangling" typo3/core-testing-* images (those tagged as ) + echo "> remove \"dangling\" ghcr.io/typo3/core-testing-* images (those tagged as )" + ${CONTAINER_BIN} images --filter "reference=ghcr.io/typo3/core-testing-*" --filter "dangling=true" --format "{{.ID}}" | xargs -I {} ${CONTAINER_BIN} rmi -f {} + echo "" + ;; + *) + loadHelp + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 + ;; +esac + +cleanUp + +# Print summary +echo "" >&2 +echo "###########################################################################" >&2 +echo "Result of ${TEST_SUITE}" >&2 +echo "Container runtime: ${CONTAINER_BIN}" >&2 +echo "PHP: ${PHP_VERSION}" >&2 +if [[ ${TEST_SUITE} =~ ^(functional|functionalDeprecated|acceptance|acceptanceInstall)$ ]]; then + case "${DBMS}" in + mariadb|mysql|postgres) + echo "DBMS: ${DBMS} version ${DBMS_VERSION} driver ${DATABASE_DRIVER}" >&2 + ;; + sqlite) + echo "DBMS: ${DBMS}" >&2 + ;; + esac +fi +if [[ -n ${EXTRA_TEST_OPTIONS} ]]; then + echo " Note: Using -e is deprecated. Simply add the options at the end of the command." + echo " Instead of: Build/Scripts/runTests.sh -s ${TEST_SUITE} -e '${EXTRA_TEST_OPTIONS}' $@" + echo " use: Build/Scripts/runTests.sh -s ${TEST_SUITE} -- ${EXTRA_TEST_OPTIONS} $@" +fi +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. +exit $SUITE_EXIT_CODE diff --git a/Build/phpstan/phpstan.ci.neon b/Build/phpstan/phpstan.ci.neon new file mode 100644 index 0000000..b576235 --- /dev/null +++ b/Build/phpstan/phpstan.ci.neon @@ -0,0 +1,5 @@ +parameters: + level: 0 + paths: + - ../../Classes + - ../../Tests diff --git a/Build/phpstan/phpstan.local.neon b/Build/phpstan/phpstan.local.neon new file mode 100644 index 0000000..b576235 --- /dev/null +++ b/Build/phpstan/phpstan.local.neon @@ -0,0 +1,5 @@ +parameters: + level: 0 + paths: + - ../../Classes + - ../../Tests diff --git a/Build/phpunit/FunctionalTests.xml b/Build/phpunit/FunctionalTests.xml new file mode 100644 index 0000000..329bdeb --- /dev/null +++ b/Build/phpunit/FunctionalTests.xml @@ -0,0 +1,29 @@ + + + + + ../../Tests/Functional + + + + + + + + + + diff --git a/Build/phpunit/UnitTests.xml b/Build/phpunit/UnitTests.xml new file mode 100644 index 0000000..ac3e89f --- /dev/null +++ b/Build/phpunit/UnitTests.xml @@ -0,0 +1,22 @@ + + + + + ../../Tests/Unit + + + + + + + + diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml new file mode 100644 index 0000000..cfd6e43 --- /dev/null +++ b/Build/testing-docker/docker-compose.yml @@ -0,0 +1,188 @@ +version: '2.3' +services: + mariadb10: + image: mariadb:10 + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + postgres10: + image: postgres:10-alpine + environment: + POSTGRES_PASSWORD: funcp + POSTGRES_USER: ${HOST_USER} + tmpfs: + - /var/lib/postgresql/data:rw,noexec,nosuid + + composer_update: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}" + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + environment: + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${TYPO3_VERSION} -eq 11 ]; then + composer req --dev --no-update \ + typo3/cms-composer-installers:^3.0 + composer req typo3/cms-core:^11.5 --no-update + fi + if [ ${TYPO3_VERSION} -eq 12 ]; then + composer req --dev --no-update \ + "typo3/cms-composer-installers:^5.0" \ + typo3/cms-backend:^12.4 \ + typo3/cms-frontend:^12.4 \ + typo3/cms-extbase:^12.4 \ + typo3/cms-fluid:^12.4 \ + typo3/cms-install:^12.4 + composer req typo3/cms-core:^12.4 -W --no-update + fi + composer update --no-progress --no-interaction; + " + + functional_mariadb10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - mariadb10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: mariadb10 + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z mariadb10 3306; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " + + functional_postgres10: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + links: + - postgres10 + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + environment: + typo3DatabaseDriver: pdo_pgsql + typo3DatabaseName: bamboo + typo3DatabaseUsername: ${HOST_USER} + typo3DatabaseHost: postgres10 + typo3DatabasePassword: funcp + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z postgres10 5432; do + sleep 1; + done; + echo Database is up; + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-postgres ${TEST_FILE}; + fi + " + + functional_sqlite: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + tmpfs: + - ${ROOT_DIR}/.Build/Web/typo3temp/var/tests/functional-sqlite-dbs/:rw,noexec,nosuid,uid=${HOST_UID} + environment: + typo3DatabaseDriver: pdo_sqlite + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} --exclude-group not-sqlite ${TEST_FILE}; + fi + " + + lint: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP'; + find . -name \\*.php ! -path "./.Build/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null + " + + unit: + image: typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: ${HOST_UID} + volumes: + - ${ROOT_DIR}:${ROOT_DIR} + working_dir: ${ROOT_DIR} + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP' + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + .Build/bin/phpunit -c Build/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + DOCKER_HOST=`route -n | awk '/^0.0.0.0/ { print $$2 }'` + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=$${DOCKER_HOST}\" \ + .Build/bin/phpunit -c Build/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " diff --git a/Tests/Functional/.gitkeep b/Tests/Functional/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Unit/Controller/BibliographyControllerTest.php b/Tests/Unit/Controller/BibliographyControllerTest.php new file mode 100644 index 0000000..fb1cbef --- /dev/null +++ b/Tests/Unit/Controller/BibliographyControllerTest.php @@ -0,0 +1,46 @@ +subject = $this->getAccessibleMock(BibliographyController::class, $methodsToMock, [$responseFactory, $streamFactory]); + } + + public function tearDown(): void + { + parent::tearDown(); + } + + /** + * @test + */ + public function indexActionReturnsHtmlResponse(): void + { + $result = $this->subject->indexAction(); + + self::assertInstanceOf(ResponseInterface::class, $result); + } + +} diff --git a/composer.json b/composer.json index f2acc24..ba2b2a0 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,11 @@ "dikastes/zotero-api": "dev-master", "illuminate/collections": "^8" }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpunit/phpunit": "^9", + "typo3/testing-framework": "^7" + }, "autoload": { "psr-4": { "Slub\\LisztBibliography\\": "Classes/" @@ -21,5 +26,32 @@ "typo3/cms": { "extension-key": "liszt_bibliography" } + }, + "scripts": { + "ci": [ "@ci:install", "@ci:php", "@ci:tests" ], + "ci:php": [ "@ci:php:stan" ], + "ci:php:stan": [ "Build/Scripts/runTests.sh -s phpstan -b docker" ], + "ci:tests": [ "@ci:tests:unit", "@ci:tests:functional" ], + "ci:tests:unit": [ "Build/Scripts/runTests.sh -s unit -b docker" ], + "ci:tests:functional": [ "Build/Scripts/runTests.sh -s functional -b docker" ], + "ci:install": [ "Build/Scripts/runTests.sh -s composerInstall -b docker" ] + }, + "config": { + "allow-plugins": { + "typo3/class-alias-loader": true, + "typo3/cms-composer-installers": true + }, + "vendor-dir": "vendor", + "bin-dir": "bin" + }, + "repositories": { + "api": { + "type": "git", + "url": "https://github.com/dikastes/zotero-api" + }, + "common": { + "type": "git", + "url": "https://github.com/dikastes/liszt_common" + } } }