SuperCacheProbe prüft beim Prüfen, ob wp_cache_post_edit die Cache-Datei einer Testseite entfernt; während der Probe ist nur der Einzelseiten-Purge erlaubt, der Pfad kommt aus home und es werden nur feste Dateinamen gelöscht. ProbeStep bündelt die Schrittlogik von Pods und WP Super Cache; ThrowawayPost hält Marker und Titel zentral und räumt auch private Probe-Seiten auf (WP Super Cache wie Pods beim Laden des Reiters). super-cache-smoke.sh prüft gegen das echte Plugin; lib.sh sperrt parallele Smoke-Läufe per flock, wp-config.php wird atomar wiederhergestellt. Doku: Host-Abhängigkeit des Einzel-Purges, WP-Cron für den Nachlauf, Komplett-Purge durch Divi beim Prüfen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
304 lines
19 KiB
Bash
304 lines
19 KiB
Bash
#!/usr/bin/env bash
|
||
# End-to-end checks of the WP Super Cache profile of the compatibility layer (plan 2026-11-06-kompatibilitaetsschicht,
|
||
# 2.5 and 2.6): status, check route /wpsc-check with the purge probe (cache off and on), the purge after a write of
|
||
# this plugin without wp_update_post (terms), the whole-cache purge after a setting, its throttle and the trailing
|
||
# purge by cron. Runs INSIDE the DDEV web container:
|
||
# cd /home/janniclas/Projekte/WordPress && timeout 600 ddev exec bash wp-content/plugins/WP-LIT-MCP/tests/Integration/super-cache-smoke.sh
|
||
#
|
||
# SIDE EFFECTS, all undone by the EXIT trap and proven at the end (verify_restored): activating WP Super Cache edits
|
||
# wp-config.php (WP_CACHE, WPCACHEHOME), creates wp-content/advanced-cache.php and wp-content/wp-cache-config.php,
|
||
# fills wp-content/cache/ and schedules wp_cache_* cron events and options. The script saves wp-config.php (and the
|
||
# files named in SAVED_FILES, if they exist) first, deactivates the plugin and writes the saved state back, byte for byte (sha256).
|
||
# It uses the plain PHP cache mode ($wp_cache_mod_rewrite = 0): no .htaccess rewrite rules are ever written; the run
|
||
# refuses to start if the cache directory is not empty, WP Super Cache is already active or WP_CACHE is already set.
|
||
set -euo pipefail
|
||
cd /var/www/html
|
||
# shellcheck source=lib.sh
|
||
source wp-content/plugins/WP-LIT-MCP/tests/Integration/lib.sh
|
||
|
||
ROOT=/var/www/html
|
||
CACHE_DIR=$ROOT/wp-content/cache
|
||
SUPERCACHE_DIR=$CACHE_DIR/supercache
|
||
WP_CONFIG=$ROOT/wp-config.php
|
||
HTACCESS=$ROOT/.htaccess
|
||
SAVED_FILES=(wp-content/advanced-cache.php wp-content/wp-cache-config.php .htaccess)
|
||
CRON_PATTERN='wp_cache|wpsc|lit_mcp_wpsc'
|
||
OPTION_PATTERN='wpsc|wp_super_cache|wp_cache|super_cache|lit_mcp_wpsc'
|
||
TRAILING_HOOK=lit_mcp_wpsc_trailing_purge
|
||
PURGED_AT=lit_mcp_wpsc_purged_at
|
||
BASE=http://localhost
|
||
|
||
ADMIN_LOGIN=$(wp user list --role=administrator --field=user_login | head -1)
|
||
PREFIX=$(wp db prefix)
|
||
|
||
# --- Guards: nothing is changed before all of them pass ------------------------------------------------------------
|
||
wp plugin is-active wp-super-cache 2>/dev/null && fail "WP Super Cache is already active; this smoke expects it inactive"
|
||
grep -Eq "^\s*(define\s*\(\s*['\"]WP_CACHE['\"]|const\s+WP_CACHE\s*=)" "$WP_CONFIG" && fail "wp-config.php already sets WP_CACHE"
|
||
[ -d "$CACHE_DIR" ] && [ -n "$(find "$CACHE_DIR" -mindepth 1 -print -quit)" ] && fail "$CACHE_DIR is not empty; refusing to touch a cache"
|
||
|
||
# --- Snapshot of everything the run can change ---------------------------------------------------------------------
|
||
BACKUP=$(mktemp -d)
|
||
sums() { sha256sum "$@" 2>/dev/null | awk '{print $1}'; }
|
||
CONFIG_SUM_BEFORE=$(sums "$WP_CONFIG")
|
||
CONFIG_STAT_BEFORE=$(stat -c '%a %U:%G' "$WP_CONFIG")
|
||
# cp -a, not -p: wp-config.php carries an ACL entry; WP Super Cache replaces the file (new inode) and loses it, and
|
||
# only cp -a writes it back with the content.
|
||
cp -a "$WP_CONFIG" "$BACKUP/wp-config.php"
|
||
[ "$(sums "$BACKUP/wp-config.php")" = "$CONFIG_SUM_BEFORE" ] || fail "could not save wp-config.php"
|
||
for f in "${SAVED_FILES[@]}"; do
|
||
if [ -e "$ROOT/$f" ]; then cp -a "$ROOT/$f" "$BACKUP/$(basename "$f")"; echo "$(sums "$ROOT/$f")" > "$BACKUP/$(basename "$f").sum"; fi
|
||
done
|
||
HTACCESS_BEFORE=absent; [ -e "$HTACCESS" ] && HTACCESS_BEFORE=$(sums "$HTACCESS")
|
||
CACHE_DIR_EXISTED=no; CACHE_DIR_MODE=775
|
||
if [ -d "$CACHE_DIR" ]; then CACHE_DIR_EXISTED=yes; CACHE_DIR_MODE=$(stat -c '%a' "$CACHE_DIR"); fi
|
||
list_hooks() { wp cron event list --fields=hook --format=csv | tail -n +2 | grep -E "$CRON_PATTERN" | sort -u || true; }
|
||
list_options() { wp db query "SELECT option_name FROM ${PREFIX}options WHERE option_name REGEXP '$OPTION_PATTERN' ORDER BY option_name" --skip-column-names; }
|
||
HOOKS_BEFORE=$(list_hooks)
|
||
OPTIONS_BEFORE=$(list_options)
|
||
ACTIVE_PLUGINS_BEFORE=$(wp option get active_plugins --format=json)
|
||
ORIGINAL_DESCRIPTION=$(wp option get blogdescription)
|
||
CREATED_POSTS=()
|
||
CREATED_TERMS=()
|
||
|
||
# --- Restore ---------------------------------------------------------------------------------------------------------
|
||
# A saved file is written back atomically: a copy next to the target (same file system), then mv – a run killed in
|
||
# the middle never leaves a half-written wp-config.php.
|
||
restore_file() { # $1 = path relative to ROOT
|
||
local name tmp; name=$(basename "$1")
|
||
if [ -e "$BACKUP/$name" ]; then
|
||
tmp=$(mktemp "$ROOT/$(dirname "$1")/.$name.restore.XXXXXX") \
|
||
&& cp -a "$BACKUP/$name" "$tmp" && mv -f "$tmp" "$ROOT/$1" || { rm -f "$tmp"; return 1; }
|
||
else
|
||
rm -f "$ROOT/$1"
|
||
fi
|
||
}
|
||
|
||
restore() {
|
||
set +e
|
||
local id term hook option
|
||
for id in "${CREATED_POSTS[@]}"; do wp post delete "$id" --force >/dev/null 2>&1; done
|
||
for term in "${CREATED_TERMS[@]}"; do wp term delete category "$term" >/dev/null 2>&1; done
|
||
wp option update blogdescription "$ORIGINAL_DESCRIPTION" >/dev/null 2>&1
|
||
wp option delete lit_mcp_wpsc_check_report lit_mcp_wpsc_releases lit_mcp_wpsc_check_lock >/dev/null 2>&1
|
||
wp transient delete "$PURGED_AT" >/dev/null 2>&1
|
||
cleanup_app_passwords_for "$ADMIN_LOGIN"
|
||
# Deactivation lets WP Super Cache undo its own edits (WP_CACHE, WPCACHEHOME, advanced-cache.php, cache files) ...
|
||
wp plugin is-active wp-super-cache >/dev/null 2>&1 && wp plugin deactivate wp-super-cache >/dev/null 2>&1
|
||
# ... and what it leaves, or does differently, is set back from the saved state.
|
||
restore_file wp-config.php
|
||
for id in "${SAVED_FILES[@]}"; do restore_file "$id"; done
|
||
[ -d "$CACHE_DIR" ] && find "$CACHE_DIR" -mindepth 1 -delete
|
||
if [ "$CACHE_DIR_EXISTED" = no ]; then
|
||
rmdir "$CACHE_DIR" 2>/dev/null
|
||
else
|
||
# Deactivation removes the whole cache directory; mkdir -m keeps the inherited ACL of its parent.
|
||
[ -d "$CACHE_DIR" ] || mkdir -m "$CACHE_DIR_MODE" "$CACHE_DIR"
|
||
fi
|
||
# The profile's cron event and every option or event the plugin added.
|
||
for hook in $(list_hooks); do
|
||
grep -qx "$hook" <<<"$HOOKS_BEFORE" || wp cron event delete "$hook" >/dev/null 2>&1
|
||
done
|
||
for option in $(list_options); do
|
||
grep -qx "$option" <<<"$OPTIONS_BEFORE" || wp option delete "$option" >/dev/null 2>&1
|
||
done
|
||
set -e
|
||
}
|
||
|
||
# Prints the proof; returns non-zero on any difference (used in the trap, so it must not exit).
|
||
verify_restored() {
|
||
local ok=0 name after
|
||
after=$(sums "$WP_CONFIG")
|
||
if [ "$after" = "$CONFIG_SUM_BEFORE" ]; then pass "restored: wp-config.php sha256 $CONFIG_SUM_BEFORE (before) == $after (after)"
|
||
else echo "FAIL: wp-config.php sha256 $CONFIG_SUM_BEFORE (before) != $after (after)"; ok=1; fi
|
||
[ "$(stat -c '%a %U:%G' "$WP_CONFIG")" = "$CONFIG_STAT_BEFORE" ] \
|
||
|| { echo "FAIL: wp-config.php mode/owner changed: $CONFIG_STAT_BEFORE -> $(stat -c '%a %U:%G' "$WP_CONFIG")"; ok=1; }
|
||
for f in "${SAVED_FILES[@]}"; do
|
||
name=$(basename "$f")
|
||
if [ -e "$BACKUP/$name" ]; then
|
||
[ "$(sums "$ROOT/$f")" = "$(cat "$BACKUP/$name.sum")" ] || { echo "FAIL: $f differs from the saved one"; ok=1; }
|
||
else
|
||
[ ! -e "$ROOT/$f" ] || { echo "FAIL: $f was absent before and exists now"; ok=1; }
|
||
fi
|
||
done
|
||
[ "$ok" = 0 ] && pass "restored: advanced-cache.php and wp-cache-config.php as before (absent: $([ -e "$BACKUP/advanced-cache.php" ] && echo no || echo yes))"
|
||
local htaccess_after=absent; [ -e "$HTACCESS" ] && htaccess_after=$(sums "$HTACCESS")
|
||
[ "$htaccess_after" = "$HTACCESS_BEFORE" ] || { echo "FAIL: .htaccess changed ($HTACCESS_BEFORE -> $htaccess_after)"; ok=1; }
|
||
if [ "$CACHE_DIR_EXISTED" = yes ]; then
|
||
[ -d "$CACHE_DIR" ] && [ -z "$(find "$CACHE_DIR" -mindepth 1 -print -quit)" ] && [ "$(stat -c '%a' "$CACHE_DIR")" = "$CACHE_DIR_MODE" ] \
|
||
|| { echo "FAIL: cache directory not empty, gone or its mode changed"; ok=1; }
|
||
else
|
||
[ ! -e "$CACHE_DIR" ] || { echo "FAIL: cache directory was absent before and exists now"; ok=1; }
|
||
fi
|
||
wp plugin is-active wp-super-cache 2>/dev/null && { echo "FAIL: WP Super Cache is still active"; ok=1; }
|
||
[ "$(wp option get active_plugins --format=json)" = "$ACTIVE_PLUGINS_BEFORE" ] || { echo "FAIL: active_plugins differs"; ok=1; }
|
||
[ "$(list_hooks)" = "$HOOKS_BEFORE" ] || { echo "FAIL: cron events differ: $(list_hooks | tr '\n' ' ')"; ok=1; }
|
||
[ "$(list_options)" = "$OPTIONS_BEFORE" ] || { echo "FAIL: options differ: $(list_options | tr '\n' ' ')"; ok=1; }
|
||
[ -z "$(wp transient get "$PURGED_AT" 2>/dev/null || true)" ] || { echo "FAIL: transient $PURGED_AT left"; ok=1; }
|
||
[ "$(wp option get blogdescription)" = "$ORIGINAL_DESCRIPTION" ] || { echo "FAIL: blogdescription not restored"; ok=1; }
|
||
[ "$(wp post list --post_type=any --post_status=any --meta_key=_lit_mcp_check_entry --format=count)" = 0 ] \
|
||
|| { echo "FAIL: a probe page is left"; ok=1; }
|
||
[ "$(wp post list --post_type=post --post_status=any --name=lit-wpsc-smoke --format=count)" = 0 ] \
|
||
|| { echo "FAIL: the test post is left"; ok=1; }
|
||
return "$ok"
|
||
}
|
||
|
||
on_exit() {
|
||
local rc=$1
|
||
restore
|
||
verify_restored || rc=1
|
||
rm -rf "$BACKUP"
|
||
guard_exit "$rc" || exit $?
|
||
exit "$rc"
|
||
}
|
||
trap 'on_exit $?' EXIT
|
||
trap 'exit 130' INT TERM HUP
|
||
|
||
# --- Helpers ---------------------------------------------------------------------------------------------------------
|
||
wpsc_component() { tool lit-site-status '{}' | jq -c '.components[] | select(.id == "wpsc")'; }
|
||
stored_option() { wp option get "$1" --format=json 2>/dev/null || true; }
|
||
event_count() { wp cron event list --hook="$TRAILING_HOOK" --format=count 2>/dev/null || echo 0; }
|
||
# The cache file of the test post as WP Super Cache keeps it (index.html; a ".needs-rebuild" copy is a purged one).
|
||
cache_file() { find "$SUPERCACHE_DIR" -type f -path '*lit-wpsc-smoke*' -name index.html 2>/dev/null | head -1; }
|
||
wait_for() { # $1 = description, rest = command; polls up to 15 s
|
||
local what=$1 i; shift
|
||
for i in $(seq 1 15); do "$@" && return 0; sleep 1; done
|
||
fail "timeout: $what"
|
||
}
|
||
cache_file_exists() { [ -n "$(cache_file)" ]; }
|
||
cache_file_gone() { [ -z "$(cache_file)" ]; }
|
||
front_page_by_wpsc() { [[ "$(curl -s -H "Host: $HOST" "$BASE/")" == *WP-Super-Cache* ]]; }
|
||
# One public request for the test post; the cache file appears at the end of the request.
|
||
fetch_post() {
|
||
local code
|
||
code=$(curl -s -o /dev/null -w '%{http_code}' -H "Host: $HOST" "$BASE$POST_PATH")
|
||
[ "$code" = 200 ] || fail "GET $POST_PATH answered $code"
|
||
}
|
||
# Requests the test post until WP Super Cache has written its file (the first request after a purge or a new post
|
||
# is not always the one that is stored).
|
||
fill_cache() {
|
||
local i
|
||
for i in $(seq 1 10); do
|
||
fetch_post
|
||
sleep 1
|
||
cache_file_exists && return 0
|
||
done
|
||
echo "--- response of $POST_PATH (selected headers) and the cache tree:"
|
||
curl -s -i -H "Host: $HOST" "$BASE$POST_PATH" | grep -iE '^(HTTP|cache-control|set-cookie)|WP Super Cache|Page not cached' | head -10
|
||
find "$CACHE_DIR" | head -20
|
||
fail "timeout: cache file of the test post"
|
||
}
|
||
config_value() { grep -E "^\s*\\\$$1\s*=" "$ROOT/wp-content/wp-cache-config.php" | head -1; }
|
||
|
||
# --- 0. Activate and look at what WP Super Cache did ------------------------------------------------------------------
|
||
wp plugin activate wp-super-cache >/dev/null 2>&1 || fail "could not activate WP Super Cache"
|
||
grep -q "define( *'WP_CACHE', *true *)" "$WP_CONFIG" || fail "activation did not set WP_CACHE (the run cannot cache)"
|
||
[ -e "$ROOT/wp-content/advanced-cache.php" ] || fail "activation did not create advanced-cache.php"
|
||
# WP Super Cache keys its files by the host of the request: MCP calls must carry the host the page was cached under.
|
||
MCP_HOST=$HOST
|
||
connect "$ADMIN_LOGIN"
|
||
|
||
# 1. Status
|
||
wpsc_component | jq -e '.active == true and .version == "3.1.5" and .problems == []' >/dev/null \
|
||
|| fail "site status must show WP Super Cache 3.1.5 active without problems: $(wpsc_component)"
|
||
pass "lit-site-status: WP Super Cache 3.1.5 active, no problems"
|
||
|
||
# 2. Check route with the cache still switched off: the probe step is green and says "not checked"
|
||
APP_PASSWORD=$(wp user application-password create "$ADMIN_LOGIN" lit-mcp-integration-test --porcelain)
|
||
run_check() {
|
||
local headers
|
||
headers=$(curl -s -o /dev/null -D - -X POST -H "Host: $HOST" -H 'X-Forwarded-Proto: https' -u "$ADMIN_LOGIN:$APP_PASSWORD" "$BASE/wp-json/lit-mcp/v1/wpsc-check")
|
||
echo "$headers" | grep -qi '^HTTP/[0-9.]* 303' || fail "check route must answer 303: $headers"
|
||
echo "$headers" | grep -qi '^location:.*tab=compatibility.*lit_mcp_notice=compat_checked' || fail "redirect to the tab: $headers"
|
||
}
|
||
[ "$(wp eval 'echo (int) ! empty($GLOBALS["cache_enabled"]);')" = 0 ] || fail "the cache must be off after activation"
|
||
run_check
|
||
REPORT=$(stored_option lit_mcp_wpsc_check_report)
|
||
echo "$REPORT" | jq -e '(.steps | length) == 2 and all(.steps[]; .problems == [] and .skipped == false)
|
||
and ([.steps[] | select(.key == "probe")] | length == 1 and (.[0].label | contains("Cache ist ausgeschaltet, nicht geprüft")))' >/dev/null \
|
||
|| fail "cache off: the report must be green and the probe must say it did not check: $REPORT"
|
||
pass "/wpsc-check with the cache off: green, probe step says 'Cache ist ausgeschaltet, nicht geprüft'"
|
||
|
||
# 3. Switch the cache on in the plain PHP mode (no mod_rewrite, no .htaccess)
|
||
wp eval 'wp_cache_enable();' >/dev/null 2>&1 || fail "wp_cache_enable failed"
|
||
# PHP-FPM's opcache re-reads a changed wp-cache-config.php at most every 2 s: wait until a public request is served
|
||
# by WP Super Cache (its HTML comment), the state the checks below need.
|
||
wait_for "WP Super Cache serves public requests" front_page_by_wpsc
|
||
config_value cache_enabled | grep -q 'true' || fail "wp-cache-config.php: cache_enabled is not true: $(config_value cache_enabled)"
|
||
config_value wp_cache_mod_rewrite | grep -Eq '= *0;' || fail "mod_rewrite mode is on: $(config_value wp_cache_mod_rewrite)"
|
||
config_value super_cache_enabled | grep -q 'true' || fail "super_cache_enabled is not true: $(config_value super_cache_enabled)"
|
||
[ "$(config_value wp_cache_clear_on_post_edit | grep -Ec '= *0;')" = 1 ] || fail "clear_on_post_edit must be 0: $(config_value wp_cache_clear_on_post_edit)"
|
||
[ ! -e "$HTACCESS" ] || [ "$(sums "$HTACCESS")" = "$HTACCESS_BEFORE" ] || fail ".htaccess changed"
|
||
pass "cache on in the plain PHP mode (mod_rewrite 0, clear_on_post_edit 0), .htaccess untouched"
|
||
|
||
# 4. Check route with the cache on: the purge probe really runs
|
||
run_check
|
||
REPORT=$(stored_option lit_mcp_wpsc_check_report)
|
||
echo "$REPORT" | jq -e '(.steps | length) == 2 and all(.steps[]; .problems == [] and .skipped == false)
|
||
and ([.steps[] | select(.key == "probe")] | length == 1 and (.[0].label | contains("nicht geprüft") | not))
|
||
and .version == "3.1.5"' >/dev/null || fail "cache on: the report must be green with a real probe step: $REPORT"
|
||
[ -z "$(stored_option lit_mcp_wpsc_check_lock)" ] || fail "the check lock must be released"
|
||
[ "$(wp post list --post_type=any --post_status=any --meta_key=_lit_mcp_check_entry --format=count)" = 0 ] || fail "the probe left a page behind"
|
||
[ "$(find "$SUPERCACHE_DIR" -path '*lit-mcp-check-*' -print -quit 2>/dev/null)" = "" ] || fail "the probe left a cache directory behind"
|
||
UNAUTH=$(curl -s -o /dev/null -w '%{http_code}' -X POST -H "Host: $HOST" -H 'X-Forwarded-Proto: https' "$BASE/wp-json/lit-mcp/v1/wpsc-check")
|
||
[ "$UNAUTH" = 401 ] || [ "$UNAUTH" = 403 ] || fail "anonymous check must be refused, got $UNAUTH"
|
||
pass "/wpsc-check with the cache on: green with the purge probe, no page or cache directory left, anonymous refused"
|
||
|
||
# 5. A published test post, fetched until it is in the cache
|
||
CAT_A=$(wp term create category "LIT WPSC Smoke A" --porcelain); CREATED_TERMS+=("$CAT_A")
|
||
CAT_B=$(wp term create category "LIT WPSC Smoke B" --porcelain); CREATED_TERMS+=("$CAT_B")
|
||
POST_ID=$(wp post create --post_type=post --post_status=publish --post_title="LIT WPSC Smoke" --post_name=lit-wpsc-smoke \
|
||
--post_content="Testbeitrag fuer den Super-Cache-Smoke." --porcelain)
|
||
CREATED_POSTS+=("$POST_ID")
|
||
POST_PATH=$(wp eval "echo wp_parse_url(get_permalink($POST_ID), PHP_URL_PATH);")
|
||
fill_cache
|
||
pass "test post $POST_ID cached: $(cache_file | sed "s#$CACHE_DIR/##")"
|
||
|
||
# 6. Control: a term change outside this plugin does not touch the cache (WP Super Cache never sees it) ...
|
||
wp post term set "$POST_ID" category "$CAT_A" >/dev/null
|
||
sleep 2
|
||
cache_file_exists || fail "control: WP Super Cache itself purged on a plain term change; the next check proves nothing"
|
||
# ... but the same kind of change through lit-content-update (no wp_update_post) empties the cache of the post.
|
||
REV=$(tool lit-content-get "{\"post_id\":$POST_ID}" | jq -r '.rev')
|
||
UPDATED=$(tool lit-content-update "{\"post_id\":$POST_ID,\"rev\":\"$REV\",\"terms\":{\"category\":[$CAT_B]}}")
|
||
echo "$UPDATED" | jq -e '.ok == true' >/dev/null || fail "lit-content-update (terms only): $UPDATED"
|
||
wait_for "the cache file of the post is gone after lit-content-update" cache_file_gone
|
||
[ "$(event_count)" = 0 ] || fail "a single-post purge must not schedule a trailing purge"
|
||
pass "terms-only lit-content-update empties the cache of the post (a plain term change does not), no trailing event"
|
||
|
||
# 7. Whole-cache purge after a setting; the second one inside 30 s is throttled and leaves exactly one cron event
|
||
fill_cache
|
||
[ -z "$(wp transient get "$PURGED_AT" 2>/dev/null || true)" ] || fail "transient $PURGED_AT set before the first whole purge"
|
||
ability lit/wp-settings-update '{"settings":{"blogdescription":"LIT WPSC Smoke 1"}}' | jq -e '.ok == true' >/dev/null || fail "settings update 1"
|
||
wait_for "the cache is empty after a setting change" cache_file_gone
|
||
wait_for "the purge time is stored" bash -c "[ -n \"\$(wp transient get $PURGED_AT 2>/dev/null)\" ]"
|
||
LAST=$(wp transient get "$PURGED_AT")
|
||
[ "$(event_count)" = 0 ] || fail "the first whole purge must not schedule a trailing purge"
|
||
pass "setting change empties the whole cache (purge time stored, no trailing event)"
|
||
|
||
fill_cache
|
||
ability lit/wp-settings-update '{"settings":{"blogdescription":"LIT WPSC Smoke 2"}}' | jq -e '.ok == true' >/dev/null || fail "settings update 2"
|
||
wait_for "one trailing purge is scheduled" bash -c "[ \"\$(wp cron event list --hook=$TRAILING_HOOK --format=count)\" = 1 ]"
|
||
sleep 2
|
||
cache_file_exists || fail "throttled: the second whole purge ran inside the lock time"
|
||
ability lit/wp-settings-update '{"settings":{"blogdescription":"LIT WPSC Smoke 3"}}' | jq -e '.ok == true' >/dev/null || fail "settings update 3"
|
||
sleep 3
|
||
[ "$(event_count)" = 1 ] || fail "exactly one trailing event must stay scheduled, found $(event_count)"
|
||
cache_file_exists || fail "throttled: the third whole purge ran inside the lock time"
|
||
[ "$(wp transient get "$PURGED_AT")" = "$LAST" ] || fail "throttled purges must not move the purge time"
|
||
pass "second and third whole purge inside 30 s: throttled (file stays, purge time unchanged), exactly one $TRAILING_HOOK event"
|
||
|
||
# 8. Run the trailing purge once the lock is over: the cache is emptied and nothing is scheduled any more
|
||
WAIT=$((LAST + 32 - $(date +%s))); [ "$WAIT" -gt 0 ] && sleep "$WAIT"
|
||
wp cron event run "$TRAILING_HOOK" >/dev/null 2>&1 || fail "wp cron event run $TRAILING_HOOK"
|
||
cache_file_gone || fail "the trailing purge did not empty the cache"
|
||
[ "$(event_count)" = 0 ] || fail "no trailing event may be left after it ran"
|
||
[ "$(wp transient get "$PURGED_AT")" -gt "$LAST" ] || fail "the trailing purge must store a new purge time"
|
||
pass "trailing purge by cron: cache emptied, event gone, purge time renewed"
|
||
|
||
# 9. Everything back as before (the EXIT trap would do it too; here it is part of the verdict)
|
||
restore
|
||
verify_restored || fail "the state before the run was not restored"
|
||
pass "cleanup: plugin inactive, test post, categories, options, transient and cron events gone"
|
||
|
||
finish
|