diff --git a/.gitattributes b/.gitattributes index 11b011cb..67ca9531 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,12 +6,10 @@ includes/ui/* linguist-language=HTML+PHP /.github export-ignore /.wordpress-org export-ignore /bin export-ignore -/docker export-ignore .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore composer.json export-ignore -docker-compose.yml export-ignore phpcs.xml export-ignore phpunit.xml.dist export-ignore -readme.txt export-ignore +readme.txt export-ignore \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a48749d6..6755b345 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,11 +1,12 @@ name: Run Tests on: - push: - pull_request: + push: null + pull_request: null jobs: - single-instance: + + instance: name: Testing (PHP ${{ matrix.php }}; Instance ${{ matrix.redis }}) runs-on: ubuntu-latest timeout-minutes: 5 @@ -36,14 +37,11 @@ jobs: --health-timeout 5s --health-retries 5 - strategy: fail-fast: false matrix: - php: [ '7.1', '7.2', '7.3', '7.4', '8.0', '8.1' ] - composer: [ 'composer' ] - redis: [ '4.0.14', '5.0.12', '6.2.6' ] - wordpress: [ 'latest' ] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + redis: ['3.2.12', '6.2.6', '7.0.3'] steps: - name: Checkout @@ -54,12 +52,12 @@ jobs: with: php-version: ${{ matrix.php }} extensions: msgpack, igbinary, redis-5.3.7 - tools: ${{ matrix.composer }} - name: Set up WordPress and WordPress Test Library uses: sjinks/setup-wordpress-test-library@master with: - version: ${{ matrix.wordpress }} + version: latest + cache_prefix: redis-cache-${{ github.ref }} - name: Install PHP Dependencies uses: ramsey/composer-install@v2 @@ -71,7 +69,7 @@ jobs: - name: Run test suite run: ./vendor/bin/phpunit - cluster-instance: + cluster: name: Testing (PHP ${{ matrix.php }}; Cluster ${{ matrix.redis }}) runs-on: ubuntu-latest timeout-minutes: 5 @@ -93,7 +91,7 @@ jobs: MYSQL_DATABASE: wordpress_test redis: - image: grokzen/redis-cluster + image: grokzen/redis-cluster:${{ matrix.redis }} ports: - '6379-6384:6379-6384' options: >- @@ -112,10 +110,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ '7.1', '7.2', '7.3', '7.4', '8.0', '8.1' ] - composer: [ 'composer' ] - redis: [ '5.0.12', '6.2.1' ] - wordpress: [ 'latest' ] + php: ['7.2', '7.3', '7.4', '8.0', '8.1'] + redis: ['5.0.12', '6.2.1'] steps: - name: Checkout @@ -126,12 +122,12 @@ jobs: with: php-version: ${{ matrix.php }} extensions: msgpack, igbinary, redis-5.3.7 - tools: ${{ matrix.composer }} - name: Set up WordPress and WordPress Test Library uses: sjinks/setup-wordpress-test-library@master with: - version: ${{ matrix.wordpress }} + version: latest + cache_prefix: redis-cache-${{ github.ref }} - name: Install PHP Dependencies uses: ramsey/composer-install@v2 diff --git a/.gitignore b/.gitignore index 044b8dad..42d892af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +/.wp-test +/.phpunit.cache /docker/apf.php /php-tools /vendor /reports +.phpunit.result.cache composer.lock +config.sh \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 76be648e..96e40d5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.1.1 + +- Bumped PHP requirement to 7.2 +- Renamed `WP_REDIS_DIR` to `WP_REDIS_PLUGIN_DIR` +- Fixed rare fatal error in diagnostics +- Allow Predis v1.1 Composer installs +- Support using `WP_REDIS_CLUSTER` string + ## 2.1.0 - Bumped PHP requirement to 7.0 diff --git a/README.md b/README.md index 0825d88f..9c574409 100644 --- a/README.md +++ b/README.md @@ -48,4 +48,4 @@ To see a list of all available WP-CLI commands, please see the [WP CLI commands ### Development -Head over to the [Docker Development wiki page](https://github.com/rhubarbgroup/redis-cache/wiki/Docker-Development) to spin up various Redis setups. +Head over to the [Local development wiki page](https://github.com/rhubarbgroup/redis-cache/wiki/Local-Development) for more information. diff --git a/bin/includes/flags-arguments.sh b/bin/includes/flags-arguments.sh deleted file mode 100644 index ae29e636..00000000 --- a/bin/includes/flags-arguments.sh +++ /dev/null @@ -1,43 +0,0 @@ -#/usr/bin/env bash -# -# Get command arguments -# Reference: https://stackoverflow.com/questions/7069682/how-to-get-arguments-with-flags-in-bash -# - -for i in ${@}; do - arguments[$index]=$i; - prev_index="$(expr $index - 1)"; - - # this if block does something akin to "where $i contains =" - # "%=*" here strips out everything from the = to the end of the argument leaving only the label - if [[ $i == *"="* ]]; then - argument_label=${i%=*} - else - argument_label=${arguments[$prev_index]} - fi - - # first argument and no label detected: must be mode then - if [[ 1 == $index && -z $argument_label ]]; then - argument_label="-m" - fi - - if [[ -n $argument_label ]]; then - # this if block only evaluates to true if the argument label exists in the variables array - if [[ -n ${variables[$argument_label]} ]]; then - # dynamically creating variables names using declare - # "#$argument_label=" here strips out the label leaving only the value - if [[ $i == *"="* ]]; then - declare ${variables[$argument_label]}=${i#$argument_label=} - else - declare ${variables[$argument_label]}=${arguments[$index]} - fi - else - # if the argument was not found store it in order - options+=(${arguments[$index]}) - fi - else - echo "unrecognized $1" - fi - - index=index+1; -done; diff --git a/bin/includes/flags-declares.sh b/bin/includes/flags-declares.sh deleted file mode 100644 index 6611faed..00000000 --- a/bin/includes/flags-declares.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!busr/bin/env bash -# -# Needed for argument extraction -# -declare -A arguments=(); -declare -A variables=(); -declare options=(); -declare -i index=1; diff --git a/bin/includes/functions.sh b/bin/includes/functions.sh deleted file mode 100644 index c9206ae2..00000000 --- a/bin/includes/functions.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bash -# -# Utility functions -# - -_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -BASE_DIR="$( dirname $( dirname "$_DIR" ))" -SRC_DIR="$BASE_DIR" -DOCKER_DIR="$BASE_DIR/docker" - -# Shorthand function for docker-compose with the right yml file -compose() { - docker-compose \ - -f "$BASE_DIR/docker-compose.yml" \ - "${@:1}" -} - -# Starts all containers and scales them accordingly -start() { - compose \ - up -d \ - --scale redis-master="${1:-0}" \ - --scale redis-slave="${2:-0}" \ - --scale redis-sentinel="${3:-0}" \ - "${@:4}" -} - -# Stops all containers -stop() { - compose down "${@}" -} - -container_info() { - docker ps -a --no-trunc \ - --format '{{ .ID }}\t{{ .Names }}\t{{ .State }}\tp:{{ .Label "com.docker.compose.project" }}' \ - | grep 'p:redis-cache' \ - | grep "$1" -} - -# Modifies the auto-prepend-file -apf() { - echo "APF-Constant $@" - ESCAPE='s/[]\/$*.^[]/\\&/g' - # --reset - if [[ '--reset' == "$1" ]]; then - apf WP_REDIS_HOST --remove - apf WP_REDIS_CLIENT --remove - apf WP_REDIS_SERVERS --remove - apf WP_REDIS_SENTINEL --remove - apf WP_REDIS_SHARDS --remove - apf WP_REDIS_CLUSTER --remove - return - fi - FILE="$DOCKER_DIR/apf.php" - # Test if apf.php exists or if it is empty - if [[ ! -f "$FILE" || ! -s "$FILE" ]]; then - cp "$DOCKER_DIR/apf-template.php" "$FILE" - fi - TMP1=$(mktemp) - CONST=$(echo "'$1'" | sed "$ESCAPE") - sed -n "/$CONST/!p" "$FILE" > "$TMP1" - if [[ '--remove' != "$2" ]]; then - TMP2=$(mktemp) - if [ -n "$3" ]; then - VALUE="[" - for var in "${@:2}"; do - VALUE="$VALUE'$var'," - done - VALUE="$VALUE]" - else - VALUE="'$2'" - fi - VALUE=$(echo "$VALUE" | sed "$ESCAPE") - INSAFTER=$(echo "// constant-definition end" | sed "$ESCAPE") - # Add constructed line before the insertion indicator end comment - REPL=$(printf ' %s => %s,' "$CONST" "$VALUE") - sed 's/^[ ]*'"$INSAFTER"'.*$/'"$REPL"'\'$'\n&/g' \ - "$TMP1" > "$TMP2" - mv "$TMP2" "$TMP1" - fi - mv "$TMP1" "$FILE" -} - -# Retrieves the IP of a docker container using its name and optionally its index -dcip() { - declare -i counter=1 - declare -i max_counter=25 - container_name="$1_${2:-1}" - while [ $counter -le $max_counter ]; do - container_state=$(container_info $container_name | awk '{print $3}') - if [ "running" = $container_state ]; then - break - fi - sleep 0.1s - ((counter++)) - done - if [ $counter -lt $max_counter ]; then - echo $(compose exec --index="${2:-1}" "$1" hostname -i) | tr -d '\r' - else - echo "$container_name" - fi -} - -# Restarts apache in the wordpress container -restart_apache() { - echo "Restarting Apache" - compose exec wordpress apachectl restart -} diff --git a/bin/run-tests.sh b/bin/run-tests.sh deleted file mode 100644 index cdd3e183..00000000 --- a/bin/run-tests.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -# -# Utility script to run phpunit unit tests -# - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -# Argument definitions -. "$DIR/includes/flags-declares.sh" -variables["-m"]="mode"; -variables["--mode"]="mode"; -variables["-f"]="force"; -variables["--force"]="force"; - -# Load libraries -. "$DIR/includes/functions.sh" -. "$DIR/includes/flags-arguments.sh" - -TESTSUITE=${mode-all} -ARG_TESTSUITE="" -CONTAINER_ID=$(container_info wordpress | awk '{print $1}') -XDEBUG_FILTER_PATH="/tmp/xdebug-filter.php" - -[ "all" != $TESTSUITE ] && ARG_TESTSUITE="--testsuite $TESTSUITE" - -# Create reports directory if missing. -[ ! -d "$BASE_DIR/reports" ] && mkdir -p "$BASE_DIR/reports" - -# Try to create xdebug filter file. -docker-compose exec wordpress test -f "$XDEBUG_FILTER_PATH" -if [ $? -eq 1 ] || [ ! -n $force ]; then - compose exec wordpress rm -rf "$XDEBUG_FILTER_PATH" - compose exec wordpress phpunit -c "/redis-cache/phpunit.xml.dist" --dump-xdebug-filter "$XDEBUG_FILTER_PATH" -fi - -# Use to provided object-cache.php instead of the one in `wp-content` -if compose exec wordpress test -f "/opt/bitnami/wordpress/wp-content/object-cache.php"; then - echo "Object cache already installed - saving object-cache.php" - compose exec wordpress cp "/opt/bitnami/wordpress/wp-content/object-cache.php" "/opt/bitnami/wordpress/wp-content/_object-cache.php" -fi -echo "Forcing WordPress to use the object-cache.php in the plugin's include directory" -compose exec wordpress bash -c 'echo " "/opt/bitnami/wordpress/wp-content/object-cache.php"' - -# Execute phpunit tests in the container. -compose exec wordpress \ - phpunit -c "/redis-cache/phpunit.xml.dist" --prepend "$XDEBUG_FILTER_PATH" $ARG_TESTSUITE - -# Retrieve code coverage report. -docker cp $CONTAINER_ID:/tmp/codecov "$BASE_DIR/reports" - -# Reset to the object-cache.php found before -if compose exec wordpress test -f "/opt/bitnami/wordpress/wp-content/_object-cache.php"; then - echo "Resetting to installed object-cache.php" - compose exec wordpress cp "/opt/bitnami/wordpress/wp-content/_object-cache.php" "/opt/bitnami/wordpress/wp-content/object-cache.php" - compose exec wordpress rm "/opt/bitnami/wordpress/wp-content/_object-cache.php" -else - echo "Resetting using object-cache.php" - compose exec wordpress rm "/opt/bitnami/wordpress/wp-content/object-cache.php" -fi \ No newline at end of file diff --git a/bin/setup-test.sh b/bin/setup-test.sh new file mode 100755 index 00000000..a64c911a --- /dev/null +++ b/bin/setup-test.sh @@ -0,0 +1,48 @@ +#! /usr/bin/env sh + +set -e + +WP_DEV_GIT=https://github.com/WordPress/wordpress-develop +WP_TESTS_DIR=.wp-test + +if [ -a config.sh ] +then + echo " - Sourcing your test environment variables" + source "config.sh" +fi + +GIT_BRANCH=${GIT_BRANCH:=trunk} + +if [[ ! -d $WP_TESTS_DIR ]]; then + echo " - Cloning wordpress develop" + git clone --depth 1 --quiet --branch $GIT_BRANCH $WP_DEV_GIT $WP_TESTS_DIR +fi + + +echo " - Creating the config file" +cp $WP_TESTS_DIR/wp-tests-config-sample.php $WP_TESTS_DIR/wp-tests-config.php + + + + +# portable in-place argument for both GNU sed and Mac OSX sed +if [[ $(uname -s) == 'Darwin' ]]; then + ioption='-i.bak' +else + ioption='-i' +fi + +DB_HOST=${DB_HOST:=127.0.0.1} +DB_PASS=${DB_PASS:=""} +DB_NAME=${DB_NAME:="wp_tests"} +DB_USER=${DB_USER:="root"} + +echo " - Setting up the database connection values" + +sed $ioption "s/youremptytestdbnamehere/${DB_NAME}/" ${WP_TESTS_DIR}/wp-tests-config.php +sed $ioption "s/yourusernamehere/${DB_USER}/" ${WP_TESTS_DIR}/wp-tests-config.php +sed $ioption "s/yourpasswordhere/${DB_PASS}/" ${WP_TESTS_DIR}/wp-tests-config.php +sed $ioption "s|localhost|${DB_HOST}|" ${WP_TESTS_DIR}/wp-tests-config.php + + +echo " - We are done ✅ \n" \ No newline at end of file diff --git a/bin/start-env.sh b/bin/start-env.sh deleted file mode 100644 index 2a566ba7..00000000 --- a/bin/start-env.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -# -# Utility script to manage the docker dev environments -# -# Documentation: -# https://github.com/rhubarbgroup/redis-cache/wiki/Docker-Development -# - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -# Argument definitions -. "$DIR/includes/flags-declares.sh" -variables["-m"]="mode"; -variables["--mode"]="mode"; -variables["-c"]="client"; -variables["--client"]="client"; - -# Load libraries -. "$DIR/includes/functions.sh" -. "$DIR/includes/flags-arguments.sh" - -case ${mode-default} in - - "default"|"-"|"simple"|"up"|"start") - start 1 0 0 "${options[@]}" - apf --reset - apf WP_REDIS_CLIENT "${client-phpredis}" - apf WP_REDIS_HOST redis-master - restart_apache - ;; - - "replication"|"repl") - start 1 3 0 "${options[@]}" - apf --reset - apf WP_REDIS_CLIENT "${client-phpredis}" - apf WP_REDIS_SERVERS \ - tcp://$(dcip redis-master):6379?alias=master \ - tcp://$(dcip redis-slave 1):6379?alias=slave-01 \ - tcp://$(dcip redis-slave 2):6379?alias=slave-02 \ - tcp://$(dcip redis-slave 3):6379?alias=slave-03 - restart_apache - ;; - - "sentinel"|"sent") - start 1 5 3 "${options[@]}" - apf --reset - apf WP_REDIS_CLIENT "${client-predis}" - apf WP_REDIS_SENTINEL master - apf WP_REDIS_SERVERS \ - tcp://$(dcip redis-sentinel 1):26379 \ - tcp://$(dcip redis-sentinel 2):26379 \ - tcp://$(dcip redis-sentinel 3):26379 - restart_apache - ;; - - "shard"|"sharding") - start 3 0 0 "${options[@]}" - apf --reset - apf WP_REDIS_CLIENT "${client-predis}" - apf WP_REDIS_SHARDS \ - tcp://$(dcip redis-master 1):6379?alias=shard-01 \ - tcp://$(dcip redis-master 2):6379?alias=shard-02 \ - tcp://$(dcip redis-master 3):6379?alias=shard-03 - restart_apache - ;; - - "cluster"|"clustering") - start 3 0 0 "${options[@]}" - apf WP_REDIS_CLIENT "${client-predis}" - apf WP_REDIS_CLUSTER \ - tcp://$(dcip redis-master 1):6379?alias=node-01 \ - tcp://$(dcip redis-master 2):6379?alias=node-02 \ - tcp://$(dcip redis-master 3):6379?alias=node-03 - restart_apache - ;; - - "stop"|"down") - stop "${options[@]}" - apf --reset - apf WP_REDIS_CLIENT "${client-phpredis}" - apf WP_REDIS_HOST redis-master - ;; - - *) echo "unrecognized command $mode" - exit - ;; - -esac diff --git a/composer.json b/composer.json index 90dd43d7..5564c69c 100644 --- a/composer.json +++ b/composer.json @@ -19,18 +19,26 @@ "wordpress" ], "require": { - "php": "^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "composer/installers": "~1.0 || ~2.0", "mnsami/composer-custom-directory-installer": "^2.0", - "predis/predis": "^2.0", + "predis/predis": "^1.1 || ^2.0", "colinmollenhour/credis": "^1.12.1" }, "require-dev": { "wp-coding-standards/wpcs": "^2.3", "phpcompatibility/phpcompatibility-wp": "^2.1", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "phpunit/phpunit": "^7.0 || ^8.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "yoast/wp-test-utils": "^1.0", + "dms/phpunit-arraysubset-asserts": "^0.4.0" }, + "autoload-dev": { + "psr-4": { + "Rhubarb\\RedisCache\\": "includes/", + "Tests\\": "tests/" + } + }, "extra": { "installer-paths": { "dependencies/predis/predis": ["predis/predis"], diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index a0909095..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,53 +0,0 @@ -version: '3.5' -services: - mariadb: - image: 'bitnami/mariadb:10.3' - volumes: - - 'mariadb_data:/bitnami/mariadb' - environment: - MARIADB_USER: bn_wordpress - MARIADB_DATABASE: bitnami_wordpress - ALLOW_EMPTY_PASSWORD: "yes" - wordpress: - build: docker/wordpress - ports: - - '80:8080' - - '443:8443' - volumes: - - 'wordpress_data:/bitnami/wordpress' - - '.:/redis-cache:ro' - depends_on: - - mariadb - - redis-master - environment: - WORDPRESS_DATABASE_HOST: mariadb - WORDPRESS_DATABASE_PORT_NUMBER: 3306 - WORDPRESS_DATABASE_USER: bn_wordpress - WORDPRESS_DATABASE_NAME: bitnami_wordpress - ALLOW_EMPTY_PASSWORD: "yes" - WORDPRESS_USERNAME: wordpress - WORDPRESS_PASSWORD: wordpress - WORDPRESS_BLOG_NAME: Redis Cache Dev - WORDPRESS_PLUGINS: query-monitor - redis-master: - build: docker/redis - ports: - - '6379:6379' - redis-slave: - build: docker/redis - command: 'redis-server --slaveof redis-master 6379' - depends_on: - - redis-master - redis-sentinel: - build: docker/redis-sentinel - depends_on: - - redis-master - environment: - MASTER_NAME: master - QUORUM: 2 - MASTER: redis-master -volumes: - mariadb_data: - driver: local - wordpress_data: - driver: local diff --git a/docker/apf-template.php b/docker/apf-template.php deleted file mode 100644 index 64bf307c..00000000 --- a/docker/apf-template.php +++ /dev/null @@ -1,13 +0,0 @@ - 'redis-master', - // constant-definition end -]; - -foreach ( $constants as $constant => $value ) { - if ( ! defined( $constant ) ) { - define( $constant, $value ); - } -} diff --git a/docker/redis-sentinel/Dockerfile b/docker/redis-sentinel/Dockerfile deleted file mode 100644 index 0353f2e8..00000000 --- a/docker/redis-sentinel/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM redis:alpine - -RUN apk add --no-cache \ - curl \ - bash - -ADD docker-entrypoint.sh / -RUN chmod +x /docker-entrypoint.sh - -EXPOSE 26379 - -ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker/redis-sentinel/docker-entrypoint.sh b/docker/redis-sentinel/docker-entrypoint.sh deleted file mode 100644 index fa8329f8..00000000 --- a/docker/redis-sentinel/docker-entrypoint.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash - -set -e - -SENTINEL_CONFIGURATION_FILE=/etc/sentinel.conf - -if [ "$AWS_IP_DISCOVERY" ]; then - ANNOUNCE_IP=`curl http://169.254.169.254/latest/meta-data/local-ipv4` -fi - -DEFAULT_REDIS_PORT=6379 -: ${REDIS_PORT:=$DEFAULT_REDIS_PORT} -: ${SENTINEL_PORT:=26379} - -# Backward compatibility fix previously existed DEFAULT_PORT -if [ "$DEFAULT_PORT" ] && [ "$REDIS_PORT" -eq $DEFAULT_REDIS_PORT ]; then - REDIS_PORT=$DEFAULT_PORT -fi - -: ${QUORUM:=2} -: ${DOWN_AFTER:=30000} -: ${FAILOVER_TIMEOUT:=180000} -: ${PARALLEL_SYNCS:=1} - -parse_addr () { - local _retvar=$1 - IFS=':' read -ra ADDR <<< "$2" - - if [ "${ADDR[1]}" = "" ]; then - ADDR[1]=$REDIS_PORT - fi - - eval $_retvar='("${ADDR[@]}")' -} - -print_slave () { - local -a ADDR - parse_addr ADDR $1 - echo "sentinel known-slave $MASTER_NAME ${ADDR[0]} ${ADDR[1]}" >> $SENTINEL_CONFIGURATION_FILE -} - -print_master () { - local -a ADDR - parse_addr ADDR $1 - echo "sentinel monitor $MASTER_NAME ${ADDR[0]} ${ADDR[1]} $QUORUM" >> $SENTINEL_CONFIGURATION_FILE -} - -echo "port $SENTINEL_PORT" > $SENTINEL_CONFIGURATION_FILE -echo "sentinel resolve-hostnames yes" > $SENTINEL_CONFIGURATION_FILE - -if [ "$ANNOUNCE_IP" ]; then - echo "sentinel announce-ip $ANNOUNCE_IP" >> $SENTINEL_CONFIGURATION_FILE -fi - -if [ "$ANNOUNCE_PORT" ]; then - echo "sentinel announce-port $ANNOUNCE_PORT" >> $SENTINEL_CONFIGURATION_FILE -fi - -if [ "$MASTER_NAME" ]; then - print_master $MASTER - echo "sentinel down-after-milliseconds $MASTER_NAME $DOWN_AFTER" >> $SENTINEL_CONFIGURATION_FILE - echo "sentinel failover-timeout $MASTER_NAME $FAILOVER_TIMEOUT" >> $SENTINEL_CONFIGURATION_FILE - echo "sentinel parallel-syncs $MASTER_NAME $PARALLEL_SYNCS" >> $SENTINEL_CONFIGURATION_FILE - - if [ "$NOTIFICATION_SCRIPT" ]; then - echo "sentinel notification-script $MASTER_NAME $NOTIFICATION_SCRIPT" >> $SENTINEL_CONFIGURATION_FILE - fi - - if [ "$CLIENT_RECONFIG_SCRIPT" ]; then - echo "sentinel client-reconfig-script $MASTER_NAME $CLIENT_RECONFIG_SCRIPT" >> $SENTINEL_CONFIGURATION_FILE - fi - - if [ "$AUTH_PASS" ]; then - echo "sentinel auth-pass $MASTER_NAME $AUTH_PASS" >> $SENTINEL_CONFIGURATION_FILE - fi - - if [ "$SLAVES" ]; then - for SLAVE in $(echo $SLAVES | tr ";" "\n") - do - if [ "$SLAVE" ]; then - print_slave $SLAVE - fi - done - fi -fi - -exec redis-server $SENTINEL_CONFIGURATION_FILE --sentinel diff --git a/docker/redis/Dockerfile b/docker/redis/Dockerfile deleted file mode 100644 index 058f6b22..00000000 --- a/docker/redis/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM redis:alpine diff --git a/docker/wordpress/Dockerfile b/docker/wordpress/Dockerfile deleted file mode 100644 index 434dea29..00000000 --- a/docker/wordpress/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM bitnami/wordpress:5 - -# Required to perform privileged actions -USER 0 - -# install apt packages -RUN install_packages php-pear autoconf build-essential lsyncd subversion vim -# Use development config -ENV PHP_DEV_CONF_FILE "/opt/bitnami/php/etc/php.ini-development" -RUN ln -sf "$PHP_DEV_CONF_FILE" /opt/bitnami/php/lib/php.ini -RUN pear config-set php_ini /opt/bitnami/php/lib/php.ini -# install xdebug using pecl -RUN pecl install xdebug -# install redis using pecl -RUN pecl install redis -# allow dependency execution -ENV PATH /redis-cache/bin:/redis-cache/vendor/bin:$PATH - -ADD ./app-entrypoint-custom.sh / -RUN chmod +x /app-entrypoint-custom.sh - -# Revert to the original non-root user -USER 1001 - -RUN rm -r /opt/bitnami/wordpress/wp-content/plugins/* - -ENTRYPOINT [ "/app-entrypoint-custom.sh" ] -CMD [ "/opt/bitnami/scripts/apache/run.sh" ] diff --git a/docker/wordpress/app-entrypoint-custom.sh b/docker/wordpress/app-entrypoint-custom.sh deleted file mode 100644 index 4fad4c0e..00000000 --- a/docker/wordpress/app-entrypoint-custom.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env bash -set -e - -# -# Initial part copied from -# https://github.com/bitnami/bitnami-docker-wordpress/blob/a0affeb00b7087bcfb81e85e1982a9419ad401c9/5/debian-10/rootfs/opt/bitnami/scripts/wordpress/entrypoint.sh -# - -# shellcheck disable=SC1091 - -set -o errexit -set -o nounset -set -o pipefail -# set -o xtrace # Uncomment this line for debugging purpose - -# Load WordPress environment -. /opt/bitnami/scripts/wordpress-env.sh - -# Load libraries -. /opt/bitnami/scripts/libbitnami.sh -. /opt/bitnami/scripts/liblog.sh -. /opt/bitnami/scripts/libwebserver.sh - -print_welcome_page - -if [[ "$1" = "/opt/bitnami/scripts/$(web_server_type)/run.sh" || "$1" = "/opt/bitnami/scripts/nginx-php-fpm/run.sh" ]]; then - info "** Starting WordPress setup **" - /opt/bitnami/scripts/"$(web_server_type)"/setup.sh - /opt/bitnami/scripts/php/setup.sh - /opt/bitnami/scripts/mysql-client/setup.sh - /opt/bitnami/scripts/wordpress/setup.sh - /post-init.sh - info "** WordPress setup finished! **" -fi - -### -# Custom actions -### - -# Load libraries -. /opt/bitnami/scripts/libfs.sh -. /opt/bitnami/scripts/libphp.sh -. /opt/bitnami/scripts/libapache.sh -. /opt/bitnami/scripts/libwordpress.sh -# Load environments -. /opt/bitnami/scripts/php-env.sh -. /opt/bitnami/scripts/apache-env.sh - -PLUGIN_SOURCE_DIR="/redis-cache" -PLUGIN_TARGET_DIR="/opt/bitnami/wordpress/wp-content/plugins/redis-cache" -APF_FILE_PATH="/redis-cache/docker/apf.php" -WP_TESTS_DIR="$WORDPRESS_BASE_DIR/tests-lib" -WP_VERSION=$(wp core version) - -# Reference: `install-wp-tests.sh` -if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then - WP_BRANCH=${WP_VERSION%\-*} - WP_TESTS_TAG="branches/$WP_BRANCH" -elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then - WP_TESTS_TAG="branches/$WP_VERSION" -elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then - if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then - # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x - WP_TESTS_TAG="tags/${WP_VERSION%??}" - else - WP_TESTS_TAG="tags/$WP_VERSION" - fi -elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then - WP_TESTS_TAG="trunk" -fi - -## Symlink generation -info "Creating plugin symlink" -if [ ! -L "$PLUGIN_TARGET_DIR" ]; then - ln -s "$PLUGIN_SOURCE_DIR" "$PLUGIN_TARGET_DIR" -fi - -## Set APF file -if [ -f "$APF_FILE_PATH" ]; then - php_conf_set auto_prepend_file "$APF_FILE_PATH" "$PHP_DEV_CONF_FILE" - info "Set PHP auto prepend file ($PHP_DEV_CONF_FILE)" -else - error "Unable to set PHP auto prepend file" - ls -lah $(dirname "$APF_FILE_PATH") | grep $(basename "$APF_FILE_PATH") -fi - -## Set xdebug config -php_conf_set xdebug.mode coverage "$PHP_DEV_CONF_FILE" - -## Download WP test suite -## Reference: https://github.com/wp-cli/scaffold-command/blob/402542fada9c17d45ffa644da1f82661c07643fd/templates/install-wp-tests.sh -if [ ! -d "$WP_TESTS_DIR" ]; then - info "Downloading WP testing suite using svn" - mkdir -p "$WP_TESTS_DIR" - svn co --quiet "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/" "$WP_TESTS_DIR/includes" - svn co --quiet "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/" "$WP_TESTS_DIR/data" -fi - -if [ ! -f "$WP_TESTS_DIR/wp-tests-config.php" ]; then - info "Creating test config" - curl --silent "https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php" > "$WP_TESTS_DIR/wp-tests-config.php" - # remove all forward slashes in the end - WP_CORE_DIR=$(echo "$WORDPRESS_BASE_DIR" | sed "s:/\+$::") - sed -i "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR/wp-tests-config.php" - sed -i "s/youremptytestdbnamehere/$WORDPRESS_DATABASE_NAME/" "$WP_TESTS_DIR/wp-tests-config.php" - sed -i "s/yourusernamehere/$WORDPRESS_DATABASE_USER/" "$WP_TESTS_DIR/wp-tests-config.php" - sed -i "s/yourpasswordhere//" "$WP_TESTS_DIR/wp-tests-config.php" - sed -i "s|localhost|${WORDPRESS_DATABASE_HOST}|" "$WP_TESTS_DIR/wp-tests-config.php" -fi - -## Create phpinfo file -info "Creating info.php file displaying phpinfo" -echo " "$WORDPRESS_BASE_DIR/info.php" - -## Set development constants -info "Setting wp-config.php development constants" -is_file_writable "$WORDPRESS_CONF_FILE" || chmod +w "$WORDPRESS_CONF_FILE" - -wordpress_conf_set WP_DEBUG true yes -wordpress_conf_set SCRIPT_DEBUG true yes -wordpress_conf_set WP_ENVIRONMENT_TYPE "local" - -wordpress_conf_set DISALLOW_FILE_EDIT true yes -wordpress_conf_set CONCATENATE_SCRIPTS false yes - -is_file_writable "$WORDPRESS_CONF_FILE" && chmod -w "$WORDPRESS_CONF_FILE" - -## Activates the newly copied plugin -info "Activating plugin and enabling dropin" -wp_execute plugin activate redis-cache -wp_execute redis update-dropin -wp_execute redis enable - -# fixes httpd already running error -apache_stop -# Needed for bitnami image - needs to be the last command! -echo "" -exec "$@" diff --git a/includes/class-plugin.php b/includes/class-plugin.php index fed3665d..db618922 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -281,7 +281,7 @@ public function enqueue_admin_styles() { return; } - wp_enqueue_style( 'redis-cache', WP_REDIS_DIR . '/assets/css/admin.css', null, WP_REDIS_VERSION ); + wp_enqueue_style( 'redis-cache', WP_REDIS_PLUGIN_DIR . '/assets/css/admin.css', null, WP_REDIS_VERSION ); } /** diff --git a/includes/diagnostics.php b/includes/diagnostics.php index 4dc889f0..2cd8f937 100644 --- a/includes/diagnostics.php +++ b/includes/diagnostics.php @@ -119,22 +119,22 @@ if ( $dropin && ! $disabled ) { $info['Global Groups'] = wp_json_encode( - array_values( $wp_object_cache->global_groups ), + array_values( $wp_object_cache->global_groups ?? [] ), JSON_PRETTY_PRINT ); $info['Ignored Groups'] = wp_json_encode( - array_values( $wp_object_cache->ignored_groups ), + array_values( $wp_object_cache->ignored_groups ?? [] ), JSON_PRETTY_PRINT ); $info['Unflushable Groups'] = wp_json_encode( - array_values( $wp_object_cache->unflushable_groups ), + array_values( $wp_object_cache->unflushable_groups ?? [] ), JSON_PRETTY_PRINT ); $info['Groups Types'] = wp_json_encode( - $wp_object_cache->group_type, + $wp_object_cache->group_type ?? null, JSON_PRETTY_PRINT ); } diff --git a/includes/object-cache.php b/includes/object-cache.php index 8b027a9a..1f96e13f 100644 --- a/includes/object-cache.php +++ b/includes/object-cache.php @@ -3,12 +3,12 @@ * Plugin Name: Redis Object Cache Drop-In * Plugin URI: https://wordpress.org/plugins/redis-cache/ * Description: A persistent object cache backend powered by Redis. Supports Predis, PhpRedis, Relay, replication, sentinels, clustering and WP-CLI. - * Version: 2.1.0 + * Version: 2.1.1 * Author: Till Krüss * Author URI: https://objectcache.pro * License: GPLv3 * License URI: http://www.gnu.org/licenses/gpl-3.0.html - * Requires PHP: 7.0 + * Requires PHP: 7.2 * * @package Rhubarb\RedisCache */ @@ -686,18 +686,22 @@ protected function connect_using_phpredis( $parameters ) { $this->diagnostics[ 'shards' ] = WP_REDIS_SHARDS; } elseif ( defined( 'WP_REDIS_CLUSTER' ) ) { - $args = [ - 'cluster' => $this->build_cluster_connection_array(), - 'timeout' => $parameters['timeout'], - 'read_timeout' => $parameters['read_timeout'], - 'persistent' => $parameters['persistent'], - ]; + if ( is_string( WP_REDIS_CLUSTER ) ) { + $this->redis = new RedisCluster( WP_REDIS_CLUSTER ); + } else { + $args = [ + 'cluster' => $this->build_cluster_connection_array(), + 'timeout' => $parameters['timeout'], + 'read_timeout' => $parameters['read_timeout'], + 'persistent' => $parameters['persistent'], + ]; - if ( isset( $parameters['password'] ) && version_compare( $version, '4.3.0', '>=' ) ) { - $args['password'] = $parameters['password']; - } + if ( isset( $parameters['password'] ) && version_compare( $version, '4.3.0', '>=' ) ) { + $args['password'] = $parameters['password']; + } - $this->redis = new RedisCluster( null, ...array_values( $args ) ); + $this->redis = new RedisCluster( null, ...array_values( $args ) ); + } $this->diagnostics += $args; } else { diff --git a/includes/ui/settings.php b/includes/ui/settings.php index 4679b714..53df4d02 100644 --- a/includes/ui/settings.php +++ b/includes/ui/settings.php @@ -98,7 +98,7 @@ class="classes() ); ?>"

- =' ); ?> + =' ); ?> =' ); ?> @@ -122,7 +122,7 @@ class="classes() ); ?>" diff --git a/languages/redis-cache.pot b/languages/redis-cache.pot index aa17af2c..cf3def5d 100644 --- a/languages/redis-cache.pot +++ b/languages/redis-cache.pot @@ -2,14 +2,14 @@ # This file is distributed under the GPLv3. msgid "" msgstr "" -"Project-Id-Version: Redis Object Cache 2.1.0\n" +"Project-Id-Version: Redis Object Cache 2.1.1\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/redis-cache\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2022-07-13T16:42:49+00:00\n" +"POT-Creation-Date: 2022-07-18T16:28:07+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.6.0\n" "X-Domain: redis-cache\n" @@ -358,7 +358,7 @@ msgstr "" #. translators: %s = PHP Version. #: includes/ui/settings.php:125 -msgid "The current version of PHP (%s) is too old. PHP 7.0 or newer is required." +msgid "The current version of PHP (%s) is too old. PHP 7.2 or newer is required." msgstr "" #: includes/ui/settings.php:134 diff --git a/phpcs.xml b/phpcs.xml index 116ce838..1b2b4250 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -9,7 +9,6 @@ . /vendor/ /dependencies/ - /docker/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 94a8f49c..7e9a1504 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,33 +1,35 @@ - - - - - - - - - - - includes - redis-cache.php - - - - - ./tests/phpunit/main - - - ./tests/phpunit/cache - - - ./tests/phpunit/meta - - + + + + + + ./tests/Feature + + + + + + includes + + + + + + + + diff --git a/readme.txt b/readme.txt index ee43160a..8f4da93b 100644 --- a/readme.txt +++ b/readme.txt @@ -1,11 +1,11 @@ === Redis Object Cache === Contributors: tillkruess Donate link: https://github.com/sponsors/tillkruss -Tags: redis, predis, phpredis, credis, pecl, relay, caching, cache, object cache, performance, replication, clustering, keydb +Tags: redis, predis, phpredis, credis, relay, caching, cache, object cache, performance, replication, clustering, keydb Requires at least: 3.3 Tested up to: 6.0 -Requires PHP: 5.6 -Stable tag: 2.1.0 +Requires PHP: 7.2 +Stable tag: 2.1.1 License: GPLv3 License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -83,6 +83,14 @@ To see a list of all available WP-CLI commands, please see the [WP CLI commands == Changelog == += 2.1.1 = + +- Bumped PHP requirement to 7.2 +- Renamed `WP_REDIS_DIR` to `WP_REDIS_PLUGIN_DIR` +- Fixed rare fatal error in diagnostics +- Allow Predis v1.1 Composer installs +- Support using `WP_REDIS_CLUSTER` string + = 2.1.0 = - Bumped PHP requirement to 7.0 @@ -564,6 +572,6 @@ Since Predis isn't maintained any longer, it's highly recommended to switch over == Upgrade Notice == -= 2.1.0 = += 2.1.1 = -Bumped PHP requirement to 7.0, updated Predis to v2.0 and deprecated Credis and HHVM clients. +Bumped PHP requirement to 7.2, updated Predis to v2.0 and deprecated Credis and HHVM clients. diff --git a/redis-cache.php b/redis-cache.php index fb1d0fbf..657e8204 100644 --- a/redis-cache.php +++ b/redis-cache.php @@ -3,11 +3,11 @@ * Plugin Name: Redis Object Cache * Plugin URI: https://wordpress.org/plugins/redis-cache/ * Description: A persistent object cache backend powered by Redis. Supports Predis, PhpRedis, Relay, replication, sentinels, clustering and WP-CLI. - * Version: 2.1.0 + * Version: 2.1.1 * Text Domain: redis-cache * Domain Path: /languages * Network: true - * Requires PHP: 7.0 + * Requires PHP: 7.2 * Author: Till Krüss * Author URI: https://objectcache.pro * GitHub Plugin URI: https://github.com/rhubarbgroup/redis-cache @@ -22,7 +22,7 @@ define( 'WP_REDIS_FILE', __FILE__ ); define( 'WP_REDIS_PLUGIN_PATH', __DIR__ ); define( 'WP_REDIS_BASENAME', plugin_basename( WP_REDIS_FILE ) ); -define( 'WP_REDIS_DIR', plugin_dir_url( WP_REDIS_FILE ) ); +define( 'WP_REDIS_PLUGIN_DIR', plugin_dir_url( WP_REDIS_FILE ) ); $meta = get_file_data( WP_REDIS_FILE, [ 'Version' => 'Version' ] ); diff --git a/tests/Feature/CacheTest.php b/tests/Feature/CacheTest.php new file mode 100644 index 00000000..129a8d00 --- /dev/null +++ b/tests/Feature/CacheTest.php @@ -0,0 +1,358 @@ +assertFalse($this->cache->get('test_miss')); + } + + public function testAddGet(): void + { + $key = __FUNCTION__; + $val = 'val'; + + $this->cache->add($key, $val); + $this->assertSame($val, $this->cache->get($key)); + } + + public function testAddGet0(): void + { + $key = __FUNCTION__; + $val = 0; + + // You can store zero in the cache. + $this->assertTrue($this->cache->add($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + } + + /** + * @ticket 20004 + */ + public function testAddGetNull(): void + { + $key = __FUNCTION__; + $val = null; + + // You can store `null` in the cache. + $this->assertTrue($this->cache->add($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + } + + /** + * @ticket 20004 + */ + public function testAddGetFalse(): void + { + $key = __FUNCTION__; + $val = false; + + // You can store `false` in the cache. + $this->assertTrue($this->cache->add($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + } + + public function testAdd(): void + { + $key = __FUNCTION__; + $val1 = 'val1'; + $val2 = 'val2'; + + // Add $key to the cache. + $this->assertTrue($this->cache->add($key, $val1)); + $this->assertSame($val1, $this->cache->get($key)); + // $key is in the cache, so reject new calls to add(). + $this->assertFalse($this->cache->add($key, $val2)); + $this->assertSame($val1, $this->cache->get($key)); + } + + public function testReplace(): void + { + $key = __FUNCTION__; + $val = 'val1'; + $val2 = 'val2'; + + // memcached rejects replace() if the key does not exist. + $this->assertFalse($this->cache->replace($key, $val)); + $this->assertFalse($this->cache->get($key)); + $this->assertTrue($this->cache->add($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + $this->assertTrue($this->cache->replace($key, $val2)); + $this->assertSame($val2, $this->cache->get($key)); + } + + public function testSet(): void + { + $key = __FUNCTION__; + $val1 = 'val1'; + $val2 = 'val2'; + + // memcached accepts set() if the key does not exist. + $this->assertTrue($this->cache->set($key, $val1)); + $this->assertSame($val1, $this->cache->get($key)); + // Second set() with same key should be allowed. + $this->assertTrue($this->cache->set($key, $val2)); + $this->assertSame($val2, $this->cache->get($key)); + } + + public function testFlush(): void + { + global $_wp_using_ext_object_cache; + + if ($_wp_using_ext_object_cache) { + $this->markTestSkipped('This test requires that an external object cache is not in use.'); + } + + $key = __FUNCTION__; + $val = 'val'; + + $this->cache->add($key, $val); + // Item is visible to both cache objects. + $this->assertSame($val, $this->cache->get($key)); + $this->cache->flush(); + // If there is no value get returns false. + $this->assertFalse($this->cache->get($key)); + } + + // Make sure objects are cloned going to and from the cache. + public function testObjectRefs(): void + { + $key = __FUNCTION__.'_1'; + $object_a = new \stdClass(); + $object_a->foo = 'alpha'; + $this->cache->set($key, $object_a); + $object_a->foo = 'bravo'; + $object_b = $this->cache->get($key); + $this->assertSame('alpha', $object_b->foo); + $object_b->foo = 'charlie'; + $this->assertSame('bravo', $object_a->foo); + + $key = __FUNCTION__.'_2'; + $object_a = new \stdClass(); + $object_a->foo = 'alpha'; + $this->cache->add($key, $object_a); + $object_a->foo = 'bravo'; + $object_b = $this->cache->get($key); + $this->assertSame('alpha', $object_b->foo); + $object_b->foo = 'charlie'; + $this->assertSame('bravo', $object_a->foo); + } + + public function testIncr(): void + { + $key = __FUNCTION__; + + $this->assertFalse($this->cache->incr($key)); + + $this->cache->set($key, 0); + $this->cache->incr($key); + $this->assertSame(1, $this->cache->get($key)); + + $this->cache->incr($key, 2); + $this->assertSame(3, $this->cache->get($key)); + } + + public function testWpCacheIncr(): void + { + $key = __FUNCTION__; + + $this->assertFalse(wp_cache_incr($key)); + + wp_cache_set($key, 0); + wp_cache_incr($key); + $this->assertSame(1, wp_cache_get($key)); + + wp_cache_incr($key, 2); + $this->assertSame(3, wp_cache_get($key)); + } + + public function testDecr(): void + { + $key = __FUNCTION__; + + $this->assertFalse($this->cache->decr($key)); + + $this->cache->set($key, 0); + $this->cache->decr($key); + $this->assertSame(0, $this->cache->get($key)); + + $this->cache->set($key, 3); + $this->cache->decr($key); + $this->assertSame(2, $this->cache->get($key)); + + $this->cache->decr($key, 2); + $this->assertSame(0, $this->cache->get($key)); + } + + /** + * @ticket 21327 + */ + public function testWpCacheDecr(): void + { + $key = __FUNCTION__; + + $this->assertFalse(wp_cache_decr($key)); + + wp_cache_set($key, 0); + wp_cache_decr($key); + $this->assertSame(0, wp_cache_get($key)); + + wp_cache_set($key, 3); + wp_cache_decr($key); + $this->assertSame(2, wp_cache_get($key)); + + wp_cache_decr($key, 2); + $this->assertSame(0, wp_cache_get($key)); + } + + public function testDelete(): void + { + $key = __FUNCTION__; + $val = 'val'; + + // Verify set. + $this->assertTrue($this->cache->set($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + + // Verify successful delete. + $this->assertTrue($this->cache->delete($key)); + $this->assertFalse($this->cache->get($key)); + + $this->assertFalse($this->cache->delete($key, 'default')); + } + + public function testWpCacheDelete(): void + { + $key = __FUNCTION__; + $val = 'val'; + + // Verify set. + $this->assertTrue(wp_cache_set($key, $val)); + $this->assertSame($val, wp_cache_get($key)); + + // Verify successful delete. + $this->assertTrue(wp_cache_delete($key)); + $this->assertFalse(wp_cache_get($key)); + + // wp_cache_delete() does not have a $force method. + // Delete returns (bool) true when key is not set and $force is true. + // $this->assertTrue( wp_cache_delete( $key, 'default', true ) ); + + $this->assertFalse(wp_cache_delete($key, 'default')); + } + + public function testSwitchToBlog(): void + { + if (!method_exists($this->cache, 'switch_to_blog')) { + $this->markTestSkipped('This test requires a switch_to_blog() method on the cache object.'); + } + + $key = __FUNCTION__; + $val = 'val1'; + $val2 = 'val2'; + + if (!is_multisite()) { + // Single site ignores switch_to_blog(). + $this->assertTrue($this->cache->set($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + $this->cache->switch_to_blog(999); + $this->assertSame($val, $this->cache->get($key)); + $this->assertTrue($this->cache->set($key, $val2)); + $this->assertSame($val2, $this->cache->get($key)); + $this->cache->switch_to_blog(get_current_blog_id()); + $this->assertSame($val2, $this->cache->get($key)); + } else { + // Multisite should have separate per-blog caches. + $this->assertTrue($this->cache->set($key, $val)); + $this->assertSame($val, $this->cache->get($key)); + $this->cache->switch_to_blog(999); + $this->assertFalse($this->cache->get($key)); + $this->assertTrue($this->cache->set($key, $val2)); + $this->assertSame($val2, $this->cache->get($key)); + $this->cache->switch_to_blog(get_current_blog_id()); + $this->assertSame($val, $this->cache->get($key)); + $this->cache->switch_to_blog(999); + $this->assertSame($val2, $this->cache->get($key)); + $this->cache->switch_to_blog(get_current_blog_id()); + $this->assertSame($val, $this->cache->get($key)); + } + + // Global group. + $this->assertTrue($this->cache->set($key, $val, 'global-cache-test')); + $this->assertSame($val, $this->cache->get($key, 'global-cache-test')); + $this->cache->switch_to_blog(999); + $this->assertSame($val, $this->cache->get($key, 'global-cache-test')); + $this->assertTrue($this->cache->set($key, $val2, 'global-cache-test')); + $this->assertSame($val2, $this->cache->get($key, 'global-cache-test')); + $this->cache->switch_to_blog(get_current_blog_id()); + $this->assertSame($val2, $this->cache->get($key, 'global-cache-test')); + } + + public function testWpCacheInit(): void + { + $new_blank_cache_object = new \WP_Object_Cache(); + wp_cache_init(); + + global $wp_object_cache; + + if (wp_using_ext_object_cache()) { + // External caches will contain property values that contain non-matching resource IDs. + $this->assertInstanceOf('WP_Object_Cache', $wp_object_cache); + } else { + $this->assertEquals($wp_object_cache, $new_blank_cache_object); + } + } + + public function testWpCacheReplace(): void + { + $key = 'my-key'; + $val1 = 'first-val'; + $val2 = 'second-val'; + + $fake_key = 'my-fake-key'; + + // Save the first value to cache and verify. + wp_cache_set($key, $val1); + $this->assertSame($val1, wp_cache_get($key)); + + // Replace the value and verify. + wp_cache_replace($key, $val2); + $this->assertSame($val2, wp_cache_get($key)); + + // Non-existent key should fail. + $this->assertFalse(wp_cache_replace($fake_key, $val1)); + + // Make sure $fake_key is not stored. + $this->assertFalse(wp_cache_get($fake_key)); + } + + /** + * @ticket 20875 + */ + public function testGetMultiple(): void + { + wp_cache_set('foo1', 'bar', 'group1'); + wp_cache_set('foo2', 'bar', 'group1'); + wp_cache_set('foo1', 'bar', 'group2'); + + $found = wp_cache_get_multiple(['foo1', 'foo2', 'foo3'], 'group1'); + + $expected = [ + 'foo1' => 'bar', + 'foo2' => 'bar', + 'foo3' => false, + ]; + + $this->assertSame($expected, $found); + } +} diff --git a/tests/Feature/PluginMetaTest.php b/tests/Feature/PluginMetaTest.php new file mode 100644 index 00000000..6cecebca --- /dev/null +++ b/tests/Feature/PluginMetaTest.php @@ -0,0 +1,166 @@ +assertNotNull($this->pluginHeaders(), 'Main plugin file not found'); + } + + public function testReadmeIncluded(): void + { + $this->assertNotNull($this->readmeHeaders(), 'Readme not found'); + } + + public function testDropInIncluded(): void + { + $this->assertNotNull($this->dropinHeaders(), 'Drop-in not found'); + } + + /** + * @depends testReadmeIncluded + * @depends testMainPluginFileIncluded + */ + public function testReadmeStableTagIsUpToDate(): void + { + $readme_data = $this->readmeHeaders(); + $plugin_data = $this->pluginHeaders(); + + $this->assertEquals( + $readme_data['StableTag'], + $plugin_data['Version'], + 'Version information between main plugin file and readme is not up to date' + ); + } + + /** + * @depends testDropInIncluded + * @depends testMainPluginFileIncluded + */ + public function testDropInVersionIsUpToDate(): void + { + $dropin_data = $this->dropinHeaders(); + $dropin_data['Name'] = trim(preg_replace('/Drop-?In/i', '', $dropin_data['Name'])); + $plugin_data = $this->pluginHeaders(); + + $this->assertArraySubset( + $dropin_data, + $plugin_data, + true, + 'Dropin file headers do not match main plugin file headers' + ); + } + + /** + * Retrieves an absolute path from the plugin's base directory. + * + * @param string $relative_path The relative path to change to an absolute one + */ + protected function basepath(string $relative_path): ?string + { + $basepath = dirname(dirname(__DIR__)); + $path = realpath(trailingslashit($basepath).$relative_path); + + return $path ?: null; + } + + /** + * Retrieves file data (headers) from a specific file if the file is readable. + * + * @param string $path The path of the file + * @param array $headers Headers to find. Format: ['key_index'=>'Header in File'] + * + * @return null|array + */ + protected function fileHeaders(string $path, array $headers): ?array + { + static $data; + if (!isset($data[$path])) { + $data[$path] = is_readable($path) + ? $this->fileData($path, $headers) + : null; + } + + return $data[$path]; + } + + /** + * Retrieves file data (headers) from a specific file. + * + * @param string $path The path of the file + * @param array $headers Headers to find. Format: ['key_index'=>'Header in File'] + * + * @return array + */ + protected function fileData(string $path, array $headers): array + { + static $data; + if (!isset($data[$path])) { + $data[$path] = get_file_data($path, $headers); + } + + return $data[$path]; + } + + protected function readmeHeaders(): ?array + { + return $this->fileHeaders( + $this->basepath(self::README_PATH), + [ + 'TestedUpTo' => 'Tested up to', + 'StableTag' => 'Stable tag', + ] + ); + } + + protected function dropinHeaders(): ?array + { + return $this->fileHeaders( + $this->basepath(self::DROPIN_PATH), + [ + 'Name' => 'Plugin Name', + 'PluginURI' => 'Plugin URI', + 'Version' => 'Version', + 'Description' => 'Description', + 'Author' => 'Author', + 'AuthorURI' => 'Author URI', + 'License' => 'License', + 'LicenseURI' => 'License URI', + ] + ); + } + + protected function pluginHeaders(): ?array + { + return $this->fileHeaders( + $this->basepath(self::PLUGIN_PATH), + [ + 'Name' => 'Plugin Name', + 'PluginURI' => 'Plugin URI', + 'Version' => 'Version', + 'Description' => 'Description', + 'Author' => 'Author', + 'AuthorURI' => 'Author URI', + 'License' => 'License', + 'LicenseURI' => 'License URI', + ] + ); + } +} diff --git a/tests/Feature/PluginTest.php b/tests/Feature/PluginTest.php new file mode 100644 index 00000000..15e7d032 --- /dev/null +++ b/tests/Feature/PluginTest.php @@ -0,0 +1,108 @@ +redis_cache()->object_cache_dropin_exists()); + } + + public function testObjectCacheDropinExistsFailure(): void + { + $target_file = WP_CONTENT_DIR.'/object-cache.php'; + $backup_file = WP_CONTENT_DIR.'/object-cache.foo.php'; + + if (copy($target_file, $backup_file)) { + unlink($target_file); + } + + self::assertFalse($this->redis_cache()->object_cache_dropin_exists()); + + if (copy($backup_file, $target_file)) { + unlink($backup_file); + } + } + + /** + * @depends testObjectCacheDropinExists + */ + public function testValidateObjectCacheDropin(): void + { + self::assertTrue($this->redis_cache()->validate_object_cache_dropin()); + } + + /** + * @depends testObjectCacheDropinExists + */ + public function testValidateObjectCacheDropinFilter(): void + { + $test = 0; + + add_filter( + 'redis_cache_validate_dropin', + function ($is_valid) use (&$test) { + ++$test; + + return $is_valid; + } + ); + + $this->redis_cache()->validate_object_cache_dropin(); + + // Test if the filter was executed exactly one time. + self::assertEquals(1, $test); + } + + /** + * @depends testObjectCacheDropinExists + */ + public function testObjectCacheDropinOutdated(): void + { + self::assertFalse($this->redis_cache()->object_cache_dropin_outdated()); + } + + /** + * Retrieves the plugin's instance. + * + * @return null|Rhubarb\RedisCache\Plugin + */ + protected function redis_cache(): ?Plugin + { + return redis_object_cache(); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 00000000..8ce229e7 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,57 @@ +cache = $this->init_cache(); + } + + public function tear_down() + { + // Your own additional tear down. + parent::tear_down(); + } + + protected function init_cache() + { + global $wp_object_cache; + + $cache_class = get_class($wp_object_cache); + $cache = new $cache_class(); + $cache->add_global_groups([ + 'global-cache-test', + 'users', + 'userlogins', + 'usermeta', + 'user_meta', + 'useremail', + 'userslugs', + 'site-transient', + 'site-options', + 'blog-lookup', + 'blog-details', + 'rss', + 'global-posts', + 'blog-id-cache', + 'networks', + 'sites', + 'site-details', + ]); + + return $cache; + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..c34bce67 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,45 @@ + ['redis-cache/redis-cache.php'], +]; + +require_once dirname(__DIR__).'/vendor/yoast/wp-test-utils/src/WPIntegration/bootstrap-functions.php'; + +/* + * Bootstrap WordPress. This will also load the Composer autoload file, the PHPUnit Polyfills + * and the custom autoloader for the TestCase and the mock object classes. + */ +WPIntegration\bootstrap_it(); + +if (!defined('WP_PLUGIN_DIR') || false === file_exists(WP_PLUGIN_DIR.'/redis-cache/redis-cache.php')) { + echo PHP_EOL, 'ERROR: Please check whether the WP_PLUGIN_DIR environment variable is set and set to the correct value. The integration test suite won\'t be able to run without it.', PHP_EOL; + + exit(1); +} + +require_once __DIR__.'/../redis-cache.php'; diff --git a/tests/phpstan/boostrap.php b/tests/phpstan/boostrap.php deleted file mode 100644 index 5512980c..00000000 --- a/tests/phpstan/boostrap.php +++ /dev/null @@ -1,20 +0,0 @@ - \true, 'QueryMonitor' => \true, 'W3_Db' => \true, 'Debug_Bar_PHP' => \true, 'WP_Hook' => \true); - protected static $ignore_method = array(); - protected static $ignore_func = array('include_once' => \true, 'require_once' => \true, 'include' => \true, 'require' => \true, 'call_user_func_array' => \true, 'call_user_func' => \true, 'trigger_error' => \true, '_doing_it_wrong' => \true, '_deprecated_argument' => \true, '_deprecated_file' => \true, '_deprecated_function' => \true, 'dbDelta' => \true); - protected static $show_args = array('do_action' => 1, 'apply_filters' => 1, 'do_action_ref_array' => 1, 'apply_filters_ref_array' => 1, 'get_template_part' => 2, 'get_extended_template_part' => 2, 'load_template' => 'dir', 'dynamic_sidebar' => 1, 'get_header' => 1, 'get_sidebar' => 1, 'get_footer' => 1, 'class_exists' => 2, 'current_user_can' => 3, 'user_can' => 4, 'current_user_can_for_blog' => 4, 'author_can' => 4); - protected static $filtered = \false; - protected $trace = \null; - protected $filtered_trace = \null; - protected $calling_line = 0; - protected $calling_file = ''; - public function __construct(array $args = array(), array $trace = \null) - { - } - public function get_stack() - { - } - public function get_caller() - { - } - public function get_component() - { - } - public static function get_frame_component(array $frame) - { - } - public function get_trace() - { - } - public function get_display_trace() - { - } - public function get_filtered_trace() - { - } - public function ignore($num) - { - } - public function ignore_current_filter() - { - } - public function filter_trace(array $frame) - { - } -} -abstract class QM_Dispatcher -{ - /** - * Outputter instances. - * - * @var QM_Output[] Array of outputters. - */ - protected $outputters = array(); - /** - * Query Monitor plugin instance. - * - * @var QM_Plugin Plugin instance. - */ - protected $qm; - public function __construct(\QM_Plugin $qm) - { - } - public abstract function is_active(); - public final function should_dispatch() - { - } - /** - * Processes and fetches the outputters for this dispatcher. - * - * @param string $outputter_id The outputter ID. - * @return QM_Output[] Array of outputters. - */ - public function get_outputters($outputter_id) - { - } - public function init() - { - } - protected function before_output() - { - } - protected function after_output() - { - } - public static function user_can_view() - { - } - public static function user_verified() - { - } - public static function editor_cookie() - { - } - public static function verify_cookie($value) - { - } -} -/** - * Timer that collects timing and memory usage. - * - * @package query-monitor - */ -class QM_Timer -{ - protected $start = \null; - protected $end = \null; - protected $trace = \null; - protected $laps = array(); - public function start(array $data = \null) - { - } - public function stop(array $data = \null) - { - } - public function lap(array $data = \null, $name = \null) - { - } - public function get_laps() - { - } - public function get_time() - { - } - public function get_memory() - { - } - public function get_start_time() - { - } - public function get_start_memory() - { - } - public function get_end_time() - { - } - public function get_end_memory() - { - } - public function get_trace() - { - } - public function end(array $data = \null) - { - } -} -abstract class QM_Plugin -{ - private $plugin = array(); - public static $minimum_php_version = '5.3.6'; - /** - * Class constructor - */ - protected function __construct($file) - { - } - /** - * Returns the URL for for a file/dir within this plugin. - * - * @param string $file The path within this plugin, e.g. '/js/clever-fx.js' - * @return string URL - */ - public final function plugin_url($file = '') - { - } - /** - * Returns the filesystem path for a file/dir within this plugin. - * - * @param string $file The path within this plugin, e.g. '/js/clever-fx.js' - * @return string Filesystem path - */ - public final function plugin_path($file = '') - { - } - /** - * Returns a version number for the given plugin file. - * - * @param string $file The path within this plugin, e.g. '/js/clever-fx.js' - * @return string Version - */ - public final function plugin_ver($file) - { - } - /** - * Returns the current plugin's basename, eg. 'my_plugin/my_plugin.php'. - * - * @return string Basename - */ - public final function plugin_base() - { - } - /** - * Populates and returns the current plugin info. - */ - private final function _plugin($item, $file = '') - { - } - public static function php_version_met() - { - } - public static function php_version_nope() - { - } -} -/** - * Plugin activation handler. - * - * @package query-monitor - */ -class QM_Activation extends \QM_Plugin -{ - protected function __construct($file) - { - } - public function activate($sitewide = \false) - { - } - public function deactivate() - { - } - public function filter_active_plugins($plugins) - { - } - public function filter_active_sitewide_plugins($plugins) - { - } - public function php_notice() - { - } - public static function init($file = \null) - { - } -} -/** - * A convenience class for wrapping certain user-facing functionality. - * - * @package query-monitor - */ -class QM -{ - public static function emergency($message, array $context = array()) - { - } - public static function alert($message, array $context = array()) - { - } - public static function critical($message, array $context = array()) - { - } - public static function error($message, array $context = array()) - { - } - public static function warning($message, array $context = array()) - { - } - public static function notice($message, array $context = array()) - { - } - public static function info($message, array $context = array()) - { - } - public static function debug($message, array $context = array()) - { - } - public static function log($level, $message, array $context = array()) - { - } -} -/** - * Mock 'Debug Bar' plugin class. - * - * @package query-monitor - */ -class Debug_Bar -{ - public $panels = array(); - public function __construct() - { - } - public function enqueue() - { - } - public function init_panels() - { - } - public function ensure_ajaxurl() - { - } - public function Debug_Bar() - { - } -} -class QM_Collectors implements \IteratorAggregate -{ - private $items = array(); - private $processed = \false; - public function getIterator() - { - } - public static function add(\QM_Collector $collector) - { - } - /** - * Fetches a collector instance. - * - * @param string $id The collector ID. - * @return QM_Collector|null The collector object. - */ - public static function get($id) - { - } - public static function init() - { - } - public function process() - { - } -} -abstract class QM_Collector -{ - protected $timer; - protected $data = array('types' => array(), 'component_times' => array()); - protected static $hide_qm = \null; - public $concerned_actions = array(); - public $concerned_filters = array(); - public $concerned_constants = array(); - public $tracked_hooks = array(); - public function __construct() - { - } - public final function id() - { - } - protected function log_type($type) - { - } - protected function maybe_log_dupe($sql, $i) - { - } - protected function log_component($component, $ltime, $type) - { - } - public static function timer_stop_float() - { - } - public static function format_bool_constant($constant) - { - } - public final function get_data() - { - } - public final function set_id($id) - { - } - public final function process_concerns() - { - } - public function filter_concerns($concerns) - { - } - public static function format_user(\WP_User $user_object) - { - } - public static function enabled() - { - } - public static function hide_qm() - { - } - public function filter_remove_qm(array $item) - { - } - public function process() - { - } - public function post_process() - { - } - public function tear_down() - { - } - public function get_timer() - { - } - public function set_timer(\QM_Timer $timer) - { - } - public function get_concerned_actions() - { - } - public function get_concerned_filters() - { - } - public function get_concerned_options() - { - } - public function get_concerned_constants() - { - } -} -/** - * Plugin CLI command. - * - * @package query-monitor - */ -class QM_CLI extends \QM_Plugin -{ - protected function __construct($file) - { - } - /** - * Enable QM by creating the symlink for db.php - */ - public function enable() - { - } - public static function init($file = \null) - { - } -} -/** - * The main Query Monitor plugin class. - * - * @package query-monitor - */ -class QueryMonitor extends \QM_Plugin -{ - protected function __construct($file) - { - } - public function filter_plugin_action_links(array $actions) - { - } - /** - * Filter a user's capabilities so they can be altered at runtime. - * - * This is used to: - * - Grant the 'view_query_monitor' capability to the user if they have the ability to manage options. - * - * This does not get called for Super Admins. - * - * @param bool[] $user_caps Array of key/value pairs where keys represent a capability name and boolean values - * represent whether the user has that capability. - * @param string[] $required_caps Required primitive capabilities for the requested capability. - * @param array $args { - * Arguments that accompany the requested capability check. - * - * @type string $0 Requested capability. - * @type int $1 Concerned user ID. - * @type mixed ...$2 Optional second and further parameters. - * } - * @param WP_User $user Concerned user object. - * @return bool[] Concerned user's capabilities. - */ - public function filter_user_has_cap(array $user_caps, array $required_caps, array $args, \WP_User $user) - { - } - public function action_plugins_loaded() - { - } - public function action_init() - { - } - public static function symlink_warning() - { - } - /** - * Registers the Query Monitor user capability group for the Members plugin. - * - * @link https://wordpress.org/plugins/members/ - */ - public function action_register_members_groups() - { - } - /** - * Registers the View Query Monitor user capability for the Members plugin. - * - * @link https://wordpress.org/plugins/members/ - */ - public function action_register_members_caps() - { - } - /** - * Registers the Query Monitor user capability group for the User Role Editor plugin. - * - * @link https://wordpress.org/plugins/user-role-editor/ - * - * @param array[] $groups Array of existing groups. - * @return array[] Updated array of groups. - */ - public function filter_ure_groups(array $groups) - { - } - /** - * Registers the View Query Monitor user capability for the User Role Editor plugin. - * - * @link https://wordpress.org/plugins/user-role-editor/ - * - * @param array[] $caps Array of existing capabilities. - * @return array[] Updated array of capabilities. - */ - public function filter_ure_caps(array $caps) - { - } - public static function init($file = \null) - { - } -} -class QM_Util -{ - protected static $file_components = array(); - protected static $file_dirs = array(); - protected static $abspath = \null; - protected static $contentpath = \null; - protected static $sort_field = \null; - private function __construct() - { - } - public static function convert_hr_to_bytes($size) - { - } - public static function standard_dir($dir, $path_replace = \null) - { - } - public static function normalize_path($path) - { - } - public static function get_file_dirs() - { - } - public static function get_file_component($file) - { - } - public static function populate_callback(array $callback) - { - } - public static function is_ajax() - { - } - public static function is_async() - { - } - public static function get_admins() - { - } - public static function is_multi_network() - { - } - public static function get_client_version($client) - { - } - public static function get_query_type($sql) - { - } - public static function display_variable($value) - { - } - /** - * Shortens a fully qualified name to reduce the length of the names of long namespaced symbols. - * - * This initialises portions that do not form the first or last portion of the name. For example: - * - * Inpsyde\Wonolog\HookListener\HookListenersRegistry->hook_callback() - * - * becomes: - * - * Inpsyde\W\H\HookListenersRegistry->hook_callback() - * - * @param string $fqn A fully qualified name. - * @return string A shortened version of the name. - */ - public static function shorten_fqn($fqn) - { - } - /** - * Helper function for JSON encoding data and formatting it in a consistent and compatible manner. - * - * @param mixed $data The data to be JSON encoded. - * @return string The JSON encoded data. - */ - public static function json_format($data) - { - } - public static function is_stringy($data) - { - } - public static function sort(array &$array, $field) - { - } - public static function rsort(array &$array, $field) - { - } - private static function _rsort($a, $b) - { - } - private static function _sort($a, $b) - { - } -} -/** - * Abstract output class for HTML pages. - * - * @package query-monitor - */ -abstract class QM_Output_Html extends \QM_Output -{ - protected static $file_link_format = \null; - protected $current_id = \null; - protected $current_name = \null; - public function name() - { - } - public function admin_menu(array $menu) - { - } - public function get_output() - { - } - protected function before_tabular_output($id = \null, $name = \null) - { - } - protected function after_tabular_output() - { - } - protected function before_non_tabular_output($id = \null, $name = \null) - { - } - protected function after_non_tabular_output() - { - } - protected function output_concerns() - { - } - protected function before_debug_bar_output($id = \null, $name = \null) - { - } - protected function after_debug_bar_output() - { - } - protected function build_notice($notice) - { - } - public static function output_inner($vars) - { - } - /** - * Returns the table filter controls. Safe for output. - * - * @param string $name The name for the `data-` attributes that get filtered by this control. - * @param string[] $values Option values for this control. - * @param string $label Label text for the filter control. - * @param array $args { - * @type string $highlight The name for the `data-` attributes that get highlighted by this control. - * @type array $prepend Associative array of options to prepend to the list of values. - * @type array $append Associative array of options to append to the list of values. - * } - * @return string Markup for the table filter controls. - */ - protected function build_filter($name, array $values, $label, $args = array()) - { - } - /** - * Returns the column sorter controls. Safe for output. - * - * @param string $heading Heading text for the column. Optional. - * @return string Markup for the column sorter controls. - */ - protected function build_sorter($heading = '') - { - } - /** - * Returns a toggle control. Safe for output. - * - * @return string Markup for the column sorter controls. - */ - protected static function build_toggler() - { - } - protected function menu(array $args) - { - } - /** - * Returns the given SQL string in a nicely presented format. Safe for output. - * - * @param string $sql An SQL query string. - * @return string The SQL formatted with markup. - */ - public static function format_sql($sql) - { - } - /** - * Returns the given URL in a nicely presented format. Safe for output. - * - * @param string $url A URL. - * @return string The URL formatted with markup. - */ - public static function format_url($url) - { - } - /** - * Returns a file path, name, and line number, or a clickable link to the file. Safe for output. - * - * @link https://querymonitor.com/blog/2019/02/clickable-stack-traces-and-function-names-in-query-monitor/ - * - * @param string $text The display text, such as a function name or file name. - * @param string $file The full file path and name. - * @param int $line Optional. A line number, if appropriate. - * @param bool $is_filename Optional. Is the text a plain file name? Default false. - * @return string The fully formatted file link or file name, safe for output. - */ - public static function output_filename($text, $file, $line = 0, $is_filename = \false) - { - } - /** - * Provides a protocol URL for edit links in QM stack traces for various editors. - * - * @param string $editor the chosen code editor - * @param string $default_format a format to use if no editor is found - * - * @return string a protocol URL format - */ - public static function get_editor_file_link_format($editor, $default_format) - { - } - public static function get_file_link_format() - { - } - public static function get_file_path_map() - { - } - public static function has_clickable_links() - { - } -} -/** - * Abstract output class for HTTP headers. - * - * @package query-monitor - */ -abstract class QM_Output_Headers extends \QM_Output -{ - public function output() - { - } -} -/** - * HTTP redirects output for HTTP headers. - * - * @package query-monitor - */ -class QM_Output_Headers_Redirects extends \QM_Output_Headers -{ - /** - * Collector instance. - * - * @var QM_Collector_Redirects Collector. - */ - protected $collector; - public function get_output() - { - } -} -/** - * General overview output for HTTP headers. - * - * @package query-monitor - */ -class QM_Output_Headers_Overview extends \QM_Output_Headers -{ - /** - * Collector instance. - * - * @var QM_Collector_Overview Collector. - */ - protected $collector; - public function get_output() - { - } -} -/** - * PHP error output for HTTP headers. - * - * @package query-monitor - */ -class QM_Output_Headers_PHP_Errors extends \QM_Output_Headers -{ - /** - * Collector instance. - * - * @var QM_Collector_PHP_Errors Collector. - */ - protected $collector; - public function get_output() - { - } -} -/** - * General overview output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Overview extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Overview Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_title(array $existing) - { - } -} -/** - * Request data output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Request extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Request Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Database query output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_DB_Queries extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_DB_Queries Collector. - */ - protected $collector; - public $query_row = 0; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - protected function output_empty_queries() - { - } - protected function output_error_queries(array $errors) - { - } - protected function output_expensive_queries(array $expensive) - { - } - protected function output_queries($name, \stdClass $db, array $data) - { - } - protected function output_query_row(array $row, array $cols) - { - } - public function admin_title(array $existing) - { - } - public function admin_class(array $class) - { - } - public function admin_menu(array $menu) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Language and locale output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Languages extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Languages Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Template and theme output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Theme extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Theme Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * PHP error output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_PHP_Errors extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_PHP_Errors Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_class(array $class) - { - } - public function admin_menu(array $menu) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Database query calling function output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_DB_Callers extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_DB_Callers Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Duplicate database query output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_DB_Dupes extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_DB_Dupes Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Template conditionals output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Conditionals extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Conditionals Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Scripts and styles output for HTML pages. - * - * @package query-monitor - */ -abstract class QM_Output_Html_Assets extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Assets Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public abstract function get_type_labels(); - public function output() - { - } - protected function dependency_row($handle, array $asset, $label) - { - } - public function _prefix_type($val) - { - } - public function admin_class(array $class) - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Enqueued scripts output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Assets_Scripts extends \QM_Output_Html_Assets -{ - /** - * Collector instance. - * - * @var QM_Collector_Assets_Scripts Collector. - */ - protected $collector; - public function name() - { - } - public function get_type_labels() - { - } -} -/** - * Timing and profiling output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Timing extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Timing Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Database query calling component output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_DB_Components extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_DB_Components Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function panel_menu(array $menu) - { - } -} -/** - * Admin screen output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Admin extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Admin Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } -} -/** - * Block editor data output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Block_Editor extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Block_Editor Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - protected static function render_block($i, array $block, array $data) - { - } - public function admin_menu(array $menu) - { - } -} -/** - * User capability checks output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Caps extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Caps Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } -} -/** - * HTTP API request output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_HTTP extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_HTTP Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_class(array $class) - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Enqueued styles output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Assets_Styles extends \QM_Output_Html_Assets -{ - /** - * Collector instance. - * - * @var QM_Collector_Assets_Styles Collector. - */ - protected $collector; - public function name() - { - } - public function get_type_labels() - { - } -} -/** - * 'Debug Bar' output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Debug_Bar extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Debug_Bar Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } -} -/** - * Hooks and actions output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Hooks extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Hooks Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public static function output_hook_table(array $hooks) - { - } -} -/** - * Environment data output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Environment extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Environment Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } -} -/** - * Request and response headers output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Headers extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Raw_Request Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - /** - * Collector name. - * - * This is unused. - * - * @return string - */ - public function name() - { - } - public function output() - { - } - public function output_request() - { - } - public function output_response() - { - } - protected function output_header_table(array $headers, $title) - { - } - public function panel_menu(array $menu) - { - } -} -/** - * PSR-3 compatible logging output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Logger extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Logger Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_class(array $class) - { - } - public function admin_menu(array $menu) - { - } -} -/** - * Transient storage output for HTML pages. - * - * @package query-monitor - */ -class QM_Output_Html_Transients extends \QM_Output_Html -{ - /** - * Collector instance. - * - * @var QM_Collector_Transients Collector. - */ - protected $collector; - public function __construct(\QM_Collector $collector) - { - } - public function name() - { - } - public function output() - { - } - public function admin_menu(array $menu) - { - } -} \ No newline at end of file diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php deleted file mode 100644 index d3aa634d..00000000 --- a/tests/phpunit/bootstrap.php +++ /dev/null @@ -1,58 +0,0 @@ - [ - 'redis-cache/redis-cache.php', - ], -]; - -if ( getenv('GH_REDIS_CLUSTER') ) { - define('WP_REDIS_CLUSTER', [ - 'tcp://127.0.0.1:6379', - 'tcp://127.0.0.1:6380', - 'tcp://127.0.0.1:6381', - 'tcp://127.0.0.1:6382', - 'tcp://127.0.0.1:6383', - 'tcp://127.0.0.1:6384', - ]); -} - -$_tests_dir = getenv('WP_TESTS_DIR'); - -if ( ! getenv('WP_TESTS_DIR') ) { - $_tests_dir = '/opt/bitnami/wordpress/tests-lib'; -} - -$base_dir = dirname( dirname( __DIR__ ) ); - -// Give access to tests_add_filter() function. -require_once $_tests_dir . '/includes/functions.php'; - -/** - * Manually load the plugin being tested. - */ -tests_add_filter( - 'muplugins_loaded', - function() use ( $base_dir ) { - require $base_dir . '/redis-cache.php'; - } -); - -// Start up the WP testing environment. -require_once $_tests_dir . '/includes/bootstrap.php'; - -// Adds composer. -require_once $base_dir . '/vendor/autoload.php'; - -require_once __DIR__ . '/class-roc-unit-test-case.php'; - -// Installs object cache -copy( - ROC_Unit_Test_Case::basepath( 'includes/object-cache.php' ), - WP_CONTENT_DIR . '/object-cache.php' -); diff --git a/tests/phpunit/cache/class-cache-test.php b/tests/phpunit/cache/class-cache-test.php deleted file mode 100644 index 54b10fc1..00000000 --- a/tests/phpunit/cache/class-cache-test.php +++ /dev/null @@ -1,352 +0,0 @@ -cache =& $this->init_cache(); - } - - function tearDown(): void { - $this->flush_cache(); - parent::tearDown(); - } - - function &init_cache() { - global $wp_object_cache; - $cache_class = get_class( $wp_object_cache ); - $cache = new $cache_class(); - $cache->add_global_groups( array( 'global-cache-test', 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details' ) ); - return $cache; - } - - function test_miss(): void { - $this->assertFalse( $this->cache->get( 'test_miss' ) ); - } - - function test_add_get(): void { - $key = __FUNCTION__; - $val = 'val'; - - $this->cache->add( $key, $val ); - $this->assertSame( $val, $this->cache->get( $key ) ); - } - - function test_add_get_0(): void { - $key = __FUNCTION__; - $val = 0; - - // You can store zero in the cache. - $this->assertTrue( $this->cache->add( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - } - - /** - * @ticket 20004 - */ - function test_add_get_null(): void { - $key = __FUNCTION__; - $val = null; - - // You can store `null` in the cache. - $this->assertTrue( $this->cache->add( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - } - - /** - * @ticket 20004 - */ - function test_add_get_false(): void { - $key = __FUNCTION__; - $val = false; - - // You can store `false` in the cache. - $this->assertTrue( $this->cache->add( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - } - - function test_add(): void { - $key = __FUNCTION__; - $val1 = 'val1'; - $val2 = 'val2'; - - // Add $key to the cache. - $this->assertTrue( $this->cache->add( $key, $val1 ) ); - $this->assertSame( $val1, $this->cache->get( $key ) ); - // $key is in the cache, so reject new calls to add(). - $this->assertFalse( $this->cache->add( $key, $val2 ) ); - $this->assertSame( $val1, $this->cache->get( $key ) ); - } - - function test_replace(): void { - $key = __FUNCTION__; - $val = 'val1'; - $val2 = 'val2'; - - // memcached rejects replace() if the key does not exist. - $this->assertFalse( $this->cache->replace( $key, $val ) ); - $this->assertFalse( $this->cache->get( $key ) ); - $this->assertTrue( $this->cache->add( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->assertTrue( $this->cache->replace( $key, $val2 ) ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - } - - function test_set(): void { - $key = __FUNCTION__; - $val1 = 'val1'; - $val2 = 'val2'; - - // memcached accepts set() if the key does not exist. - $this->assertTrue( $this->cache->set( $key, $val1 ) ); - $this->assertSame( $val1, $this->cache->get( $key ) ); - // Second set() with same key should be allowed. - $this->assertTrue( $this->cache->set( $key, $val2 ) ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - } - - function test_flush(): void { - global $_wp_using_ext_object_cache; - - if ( $_wp_using_ext_object_cache ) { - $this->markTestSkipped( 'This test requires that an external object cache is not in use.' ); - } - - $key = __FUNCTION__; - $val = 'val'; - - $this->cache->add( $key, $val ); - // Item is visible to both cache objects. - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->cache->flush(); - // If there is no value get returns false. - $this->assertFalse( $this->cache->get( $key ) ); - } - - // Make sure objects are cloned going to and from the cache. - function test_object_refs(): void { - $key = __FUNCTION__ . '_1'; - $object_a = new stdClass; - $object_a->foo = 'alpha'; - $this->cache->set( $key, $object_a ); - $object_a->foo = 'bravo'; - $object_b = $this->cache->get( $key ); - $this->assertSame( 'alpha', $object_b->foo ); - $object_b->foo = 'charlie'; - $this->assertSame( 'bravo', $object_a->foo ); - - $key = __FUNCTION__ . '_2'; - $object_a = new stdClass; - $object_a->foo = 'alpha'; - $this->cache->add( $key, $object_a ); - $object_a->foo = 'bravo'; - $object_b = $this->cache->get( $key ); - $this->assertSame( 'alpha', $object_b->foo ); - $object_b->foo = 'charlie'; - $this->assertSame( 'bravo', $object_a->foo ); - } - - function test_incr(): void { - $key = __FUNCTION__; - - $this->assertFalse( $this->cache->incr( $key ) ); - - $this->cache->set( $key, 0 ); - $this->cache->incr( $key ); - $this->assertSame( 1, $this->cache->get( $key ) ); - - $this->cache->incr( $key, 2 ); - $this->assertSame( 3, $this->cache->get( $key ) ); - } - - function test_wp_cache_incr(): void { - $key = __FUNCTION__; - - $this->assertFalse( wp_cache_incr( $key ) ); - - wp_cache_set( $key, 0 ); - wp_cache_incr( $key ); - $this->assertSame( 1, wp_cache_get( $key ) ); - - wp_cache_incr( $key, 2 ); - $this->assertSame( 3, wp_cache_get( $key ) ); - } - - function test_decr(): void { - $key = __FUNCTION__; - - $this->assertFalse( $this->cache->decr( $key ) ); - - $this->cache->set( $key, 0 ); - $this->cache->decr( $key ); - $this->assertSame( 0, $this->cache->get( $key ) ); - - $this->cache->set( $key, 3 ); - $this->cache->decr( $key ); - $this->assertSame( 2, $this->cache->get( $key ) ); - - $this->cache->decr( $key, 2 ); - $this->assertSame( 0, $this->cache->get( $key ) ); - } - - /** - * @ticket 21327 - */ - function test_wp_cache_decr(): void { - $key = __FUNCTION__; - - $this->assertFalse( wp_cache_decr( $key ) ); - - wp_cache_set( $key, 0 ); - wp_cache_decr( $key ); - $this->assertSame( 0, wp_cache_get( $key ) ); - - wp_cache_set( $key, 3 ); - wp_cache_decr( $key ); - $this->assertSame( 2, wp_cache_get( $key ) ); - - wp_cache_decr( $key, 2 ); - $this->assertSame( 0, wp_cache_get( $key ) ); - } - - function test_delete(): void { - $key = __FUNCTION__; - $val = 'val'; - - // Verify set. - $this->assertTrue( $this->cache->set( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - - // Verify successful delete. - $this->assertTrue( $this->cache->delete( $key ) ); - $this->assertFalse( $this->cache->get( $key ) ); - - $this->assertFalse( $this->cache->delete( $key, 'default' ) ); - } - - function test_wp_cache_delete(): void { - $key = __FUNCTION__; - $val = 'val'; - - // Verify set. - $this->assertTrue( wp_cache_set( $key, $val ) ); - $this->assertSame( $val, wp_cache_get( $key ) ); - - // Verify successful delete. - $this->assertTrue( wp_cache_delete( $key ) ); - $this->assertFalse( wp_cache_get( $key ) ); - - // wp_cache_delete() does not have a $force method. - // Delete returns (bool) true when key is not set and $force is true. - // $this->assertTrue( wp_cache_delete( $key, 'default', true ) ); - - $this->assertFalse( wp_cache_delete( $key, 'default' ) ); - } - - function test_switch_to_blog(): void { - if ( ! method_exists( $this->cache, 'switch_to_blog' ) ) { - $this->markTestSkipped( 'This test requires a switch_to_blog() method on the cache object.' ); - } - - $key = __FUNCTION__; - $val = 'val1'; - $val2 = 'val2'; - - if ( ! is_multisite() ) { - // Single site ignores switch_to_blog(). - $this->assertTrue( $this->cache->set( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( 999 ); - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->assertTrue( $this->cache->set( $key, $val2 ) ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( get_current_blog_id() ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - } else { - // Multisite should have separate per-blog caches. - $this->assertTrue( $this->cache->set( $key, $val ) ); - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( 999 ); - $this->assertFalse( $this->cache->get( $key ) ); - $this->assertTrue( $this->cache->set( $key, $val2 ) ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( get_current_blog_id() ); - $this->assertSame( $val, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( 999 ); - $this->assertSame( $val2, $this->cache->get( $key ) ); - $this->cache->switch_to_blog( get_current_blog_id() ); - $this->assertSame( $val, $this->cache->get( $key ) ); - } - - // Global group. - $this->assertTrue( $this->cache->set( $key, $val, 'global-cache-test' ) ); - $this->assertSame( $val, $this->cache->get( $key, 'global-cache-test' ) ); - $this->cache->switch_to_blog( 999 ); - $this->assertSame( $val, $this->cache->get( $key, 'global-cache-test' ) ); - $this->assertTrue( $this->cache->set( $key, $val2, 'global-cache-test' ) ); - $this->assertSame( $val2, $this->cache->get( $key, 'global-cache-test' ) ); - $this->cache->switch_to_blog( get_current_blog_id() ); - $this->assertSame( $val2, $this->cache->get( $key, 'global-cache-test' ) ); - } - - function test_wp_cache_init(): void { - $new_blank_cache_object = new WP_Object_Cache(); - wp_cache_init(); - - global $wp_object_cache; - - if ( wp_using_ext_object_cache() ) { - // External caches will contain property values that contain non-matching resource IDs. - $this->assertInstanceOf( 'WP_Object_Cache', $wp_object_cache ); - } else { - $this->assertEquals( $wp_object_cache, $new_blank_cache_object ); - } - } - - function test_wp_cache_replace(): void { - $key = 'my-key'; - $val1 = 'first-val'; - $val2 = 'second-val'; - - $fake_key = 'my-fake-key'; - - // Save the first value to cache and verify. - wp_cache_set( $key, $val1 ); - $this->assertSame( $val1, wp_cache_get( $key ) ); - - // Replace the value and verify. - wp_cache_replace( $key, $val2 ); - $this->assertSame( $val2, wp_cache_get( $key ) ); - - // Non-existent key should fail. - $this->assertFalse( wp_cache_replace( $fake_key, $val1 ) ); - - // Make sure $fake_key is not stored. - $this->assertFalse( wp_cache_get( $fake_key ) ); - } - - /** - * @ticket 20875 - */ - public function test_get_multiple(): void { - wp_cache_set( 'foo1', 'bar', 'group1' ); - wp_cache_set( 'foo2', 'bar', 'group1' ); - wp_cache_set( 'foo1', 'bar', 'group2' ); - - $found = wp_cache_get_multiple( array( 'foo1', 'foo2', 'foo3' ), 'group1' ); - - $expected = array( - 'foo1' => 'bar', - 'foo2' => 'bar', - 'foo3' => false, - ); - - $this->assertSame( $expected, $found ); - } -} diff --git a/tests/phpunit/class-roc-unit-test-case.php b/tests/phpunit/class-roc-unit-test-case.php deleted file mode 100644 index d7b0dbed..00000000 --- a/tests/phpunit/class-roc-unit-test-case.php +++ /dev/null @@ -1,73 +0,0 @@ -redis_cache ) ) { - $this->redis_cache = redis_object_cache(); - } - return $this->redis_cache; - } - - /** - * Retrieves an absolute path from the plugin's base directory - * - * @param string $relative_path The relative path to change to an absolute one - * @return null|string - */ - public static function basepath( string $relative_path ) : ?string { - $basepath = dirname( dirname( __DIR__ ) ); - $path = realpath( trailingslashit( $basepath ) . $relative_path ); - return $path ?: null; - } - - /** - * Retrieves file data (headers) from a specific file - * - * @param string $path The path of the file - * @param array $headers Headers to find. Format: ['key_index'=>'Header in File'] - * @return array - */ - protected static function fileData( string $path, array $headers ) : array { - static $data; - if ( ! isset( $data[ $path ] ) ) { - $data[ $path ] = get_file_data( $path, $headers ); - } - return $data[ $path ]; - } - - /** - * Retrieves file data (headers) from a specific file if the file is readable - * - * @param string $path The path of the file - * @param array $headers Headers to find. Format: ['key_index'=>'Header in File'] - * @return null|array - */ - protected static function fileHeaders( string $path, array $headers ) : ?array { - static $data; - if ( ! isset( $data[ $path ] ) ) { - $data[ $path ] = is_readable( $path ) - ? self::fileData( $path, $headers ) - : null; - } - - return $data[ $path ]; - } - -} diff --git a/tests/phpunit/main/class-plugin-test.php b/tests/phpunit/main/class-plugin-test.php deleted file mode 100644 index 1f1cd448..00000000 --- a/tests/phpunit/main/class-plugin-test.php +++ /dev/null @@ -1,72 +0,0 @@ -redis_cache()->object_cache_dropin_exists() ); - } - - public function test_object_cache_dropin_exists_failure() : void { - $target_file = WP_CONTENT_DIR . '/object-cache.php'; - $backup_file = WP_CONTENT_DIR . '/object-cache.foo.php'; - if ( copy( $target_file, $backup_file ) ) { - unlink( $target_file ); - } - self::assertFalse( $this->redis_cache()->object_cache_dropin_exists() ); - if ( copy( $backup_file, $target_file ) ) { - unlink( $backup_file ); - } - } - - /** - * @depends test_object_cache_dropin_exists - */ - public function test_validate_object_cache_dropin() : void { - self::assertTrue( $this->redis_cache()->validate_object_cache_dropin() ); - } - - /** - * @depends test_object_cache_dropin_exists - */ - public function test_validate_object_cache_dropin_filter() : void { - $test = 0; - add_filter( - 'redis_cache_validate_dropin', - function( $is_valid ) use ( &$test ) { - $test++; - return $is_valid; - } - ); - $this->redis_cache()->validate_object_cache_dropin(); - // Test if the filter was executed exactly one time. - self::assertEquals( 1, $test ); - } - - /** - * @depends test_object_cache_dropin_exists - */ - public function test_object_cache_dropin_outdated() : void { - self::assertFalse( $this->redis_cache()->object_cache_dropin_outdated() ); - } - -} diff --git a/tests/phpunit/meta/class-plugin-meta-test.php b/tests/phpunit/meta/class-plugin-meta-test.php deleted file mode 100644 index 759b0146..00000000 --- a/tests/phpunit/meta/class-plugin-meta-test.php +++ /dev/null @@ -1,107 +0,0 @@ - 'Tested up to', - 'StableTag' => 'Stable tag', - ] - ); - } - - private function dropinHeaders() : ?array { - return self::fileHeaders( - self::basepath( self::DROPIN_PATH ), - [ - 'Name' => 'Plugin Name', - 'PluginURI' => 'Plugin URI', - 'Version' => 'Version', - 'Description' => 'Description', - 'Author' => 'Author', - 'AuthorURI' => 'Author URI', - 'License' => 'License', - 'LicenseURI' => 'License URI', - ] - ); - } - - private function pluginHeaders() : ?array { - return self::fileHeaders( - self::basepath( self::PLUGIN_PATH ), - [ - 'Name' => 'Plugin Name', - 'PluginURI' => 'Plugin URI', - 'Version' => 'Version', - 'Description' => 'Description', - 'Author' => 'Author', - 'AuthorURI' => 'Author URI', - 'License' => 'License', - 'LicenseURI' => 'License URI', - ] - ); - } - -}