Files
WP-LIT-MCP/tests/Integration/divi-release-smoke.sh
T

115 lines
7.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# End-to-end checks of the Divi release gate (spec 2026-09-29-divi-absicherung).
# Runs INSIDE the DDEV web container (Divi 5.2.1 must be the active theme):
# cd /home/janniclas/Projekte/WordPress && timeout 900 ddev exec bash wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-release-smoke.sh
# Leaves nothing behind: pages, the check report, the check lock, the state transient and the application password
# are removed again.
set -euo pipefail
cd /var/www/html
# shellcheck source=lib.sh
source wp-content/plugins/WP-LIT-MCP/tests/Integration/lib.sh
ADMIN_LOGIN=$(wp user list --role=administrator --field=user_login | head -1)
CREATED_POSTS=()
BASE=http://localhost
cleanup() {
for id in "${CREATED_POSTS[@]}"; do
wp post delete "$id" --force >/dev/null 2>&1 || true
done
wp option delete lit_mcp_divi_check_report lit_mcp_divi_check_lock >/dev/null 2>&1 || true
wp transient delete lit_mcp_divi_state >/dev/null 2>&1 || true
cleanup_app_passwords_for "$ADMIN_LOGIN"
}
trap 'rc=$?; cleanup; guard_exit "$rc" || exit $?' EXIT
check_pages() { wp post list --post_type=page --post_status=any --meta_key=_lit_mcp_check_page --format=count; }
[ "$(wp eval 'echo get_template();')" = "Divi" ] || fail "Divi must be the active theme"
# 1. Code, registrations and fingerprints match Divi 5.2.1
[ "$(wp eval 'echo wp_json_encode((new LIT\MCP\Integrations\Divi\DiviCompatibility())->problems());')" = "[]" ] \
|| fail "Divi compatibility problems under WP-CLI"
pass "manifests and fingerprints match the installed Divi"
connect "$ADMIN_LOGIN"
STATUS=$(tool lit-site-status '{}')
echo "$STATUS" | jq -e '.components[] | select(.id == "divi") | .problems == [] and .release.state == "released" and .release.source == "code"' >/dev/null \
|| fail "site status must show Divi released from code: $STATUS"
pass "lit-site-status: Divi 5.2.1 released (code), no problems in an MCP request"
# 2. Admin check through the REST route (application password instead of the cookie nonce).
# X-Forwarded-Proto: https is required here: without it the request to http://localhost with the
# site's own Host header never reaches the route (a 404 before any auth check even runs), the same
# header mcp-smoke.sh and tb-smoke.sh already send for their own curl calls against this DDEV site.
APP_PASSWORD=$(wp user application-password create "$ADMIN_LOGIN" lit-mcp-integration-test --porcelain)
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/divi-check")
echo "$HEADERS" | grep -qi '^HTTP/[0-9.]* 303' || fail "check route must answer 303: $HEADERS"
echo "$HEADERS" | grep -qi '^location:.*tab=divi.*lit_mcp_notice=divi_checked' || fail "redirect to the tab: $HEADERS"
REPORT=$(wp option get lit_mcp_divi_check_report --format=json)
echo "$REPORT" | jq -e '[.steps[] | (.problems == [] and .skipped == false)] | all and length == 5' >/dev/null \
|| fail "every check step must be green: $REPORT"
[ "$(check_pages)" = "0" ] || fail "the throwaway page must be gone"
[ "$(wp option get lit_mcp_divi_check_lock 2>/dev/null || true)" = "" ] || fail "the check lock must be released"
pass "admin check (REST): five green steps, throwaway page deleted, lock released"
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/divi-check")
[ "$UNAUTH" = "401" ] || [ "$UNAUTH" = "403" ] || fail "anonymous check must be refused, got $UNAUTH"
pass "check route refuses anonymous requests"
# 3. Incompatible Divi (simulated: a failed fingerprint in the state cache) locks every write path
wp eval '
$key = LIT\MCP\Integrations\Divi\Release\ReleaseResolver::stateKey((string) LIT\MCP\Integrations\Divi\Release\DiviEnvironment::version());
set_transient(LIT\MCP\Integrations\Divi\Release\ReleaseResolver::CACHE, ["key" => $key, "problems" => ["Smoke: Nachbau geändert"]], 600);'
PAGE_ID=$(wp --user="$ADMIN_LOGIN" post create --post_type=page --post_status=draft --post_title="LIT Freigabe Smoke" --porcelain)
CREATED_POSTS+=("$PAGE_ID")
wp post meta update "$PAGE_ID" _et_pb_use_builder on >/dev/null
wp post meta update "$PAGE_ID" _et_pb_use_divi_5 on >/dev/null
BEFORE=$(wp post get "$PAGE_ID" --field=post_content)
OUTLINE=$(tool lit-divi-outline "{\"post_id\":$PAGE_ID}")
echo "$OUTLINE" | jq -e '.warnings | any(test("inkompatibel"))' >/dev/null || fail "read tool must carry the notice: $OUTLINE"
pass "reading Divi tool runs and warns"
INSERT=$(tool lit-divi-insert "{\"post_id\":$PAGE_ID,\"tree_rev\":$(echo "$OUTLINE" | jq '.tree_rev'),\"nodes\":[{\"type\":\"section\",\"modules\":[{\"type\":\"text\",\"content\":\"<p>x</p>\"}]}]}")
echo "$INSERT" | jq -e '.__error | fromjson | .code == "divi_incompatible"' >/dev/null || fail "write must be refused: $INSERT"
[ "$(wp post get "$PAGE_ID" --field=post_content)" = "$BEFORE" ] || fail "nothing may be written"
pass "writing Divi tool refused with divi_incompatible, page unchanged"
CREATE=$(tool lit-content-create '{"post_type":"page","title":"LIT Freigabe Smoke Neu","divi":[{"type":"section","modules":[{"type":"text","content":"<p>x</p>"}]}]}')
echo "$CREATE" | jq -e '.__error | fromjson | .code == "divi_incompatible"' >/dev/null || fail "content-create with divi must be refused: $CREATE"
[ "$(wp post list --post_type=page --post_status=any --title='LIT Freigabe Smoke Neu' --format=count)" = "0" ] \
|| fail "no draft may remain"
pass "lit-content-create with divi refused before a draft exists"
STATUS=$(tool lit-site-status '{}')
echo "$STATUS" | jq -e '.components[] | select(.id == "divi") | .release.state == "incompatible"' >/dev/null \
|| fail "site status must show incompatible: $STATUS"
# wp db query --skip-column-names misreports this as a write query (it treats "insert" anywhere in the SQL,
# even inside a quoted value like 'lit/divi-insert', as an INSERT and prints "Rows affected" instead of the
# result) - wp eval with $wpdb->get_var() runs the same COUNT() reliably.
REFUSED_LOGGED=$(wp eval '
global $wpdb;
echo (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}lit_mcp_log WHERE result = %s AND ability = %s",
"refused",
"lit/divi-insert"
));')
[ "$REFUSED_LOGGED" -ge 1 ] || fail "the refusal must be in the change log"
pass "site status incompatible, refusal logged"
# 4. Back to released: writes work again
wp transient delete lit_mcp_divi_state >/dev/null
OUTLINE=$(tool lit-divi-outline "{\"post_id\":$PAGE_ID}")
INSERT=$(tool lit-divi-insert "{\"post_id\":$PAGE_ID,\"tree_rev\":$(echo "$OUTLINE" | jq '.tree_rev'),\"nodes\":[{\"type\":\"section\",\"modules\":[{\"type\":\"text\",\"content\":\"<p>x</p>\"}]}]}")
echo "$INSERT" | jq -e '.ok == true' >/dev/null || fail "write must work when released: $INSERT"
pass "released again: writing works"
# 5. WP-CLI
wp --user="$ADMIN_LOGIN" lit-mcp divi-check >/dev/null || fail "wp lit-mcp divi-check must succeed"
[ "$(check_pages)" = "0" ] || fail "the CLI check must delete its page"
pass "wp lit-mcp divi-check is green and leaves no page"
finish