Skip to main content

WPStack

How to Test WordPress Sandbox Reset, Expiry and Deletion End to End

How to Test WordPress Sandbox Reset, Expiry and Deletion End to End
September 13, 2026
No Comments

A WordPress sandbox test passes only when the temporary site works, expires and leaves no residue. Opening the demo homepage proves almost nothing about token replay, reset integrity, delayed cron, partial deletion or orphaned users. Test the complete state transition from launch request to independently verified absence.

Define the lifecycle before automating it

Write the allowed states and transitions: requested, provisioning, active, extending, resetting, expired, deleting, deleted and failed. For every transition, specify the trigger, database record, visible result, side effects, timeout, retry policy and rollback. Impossible transitions—such as extending a deleted session—must fail safely.

StagePrimary assertionIndependent evidence
CreateOne isolated site/account existsSite list, session registry, unique IDs
LoginToken works once for intended accountReplay fails; cookie belongs to sandbox
UseRequired plugin workflow succeedsDenied-action matrix still fails
ExtendExpiry changes within policyOld deadline replaced atomically
ResetKnown seed baseline returnsMutation set disappears; identity rules hold
ExpireAccess stops at server boundaryExisting and new requests are denied
DeleteOwned resources are removedSite, user, tables and files absent
ReconcileNo orphan remainsTwo-way inventory comparison is clean

Build deterministic test data

Seed a small fixture with posts, media, plugin settings and one background job. Mark every generated resource with the test run/session ID. Avoid real customer data and external credentials. The marker lets the test prove isolation and find residue without relying on a human-readable subdomain.

Test provisioning as a transaction

Inject failure after site creation, after user creation, during plugin activation and during seed import. Each failure should either roll back immediately or create a visible cleanup obligation with a retry. Retrying the same request must not create duplicate sites. Test simultaneous identical launch requests to expose race conditions.

Verify login and authorization

Consume the launch token once and replay it from a second clean browser; replay must fail. Verify token expiry, account binding and revocation after reset. Exercise required actions, then attempt direct Network Admin access, user promotion, plugin installation, REST/AJAX mutations, email and external HTTP. A hidden menu is not proof of denial.

Test reset semantics explicitly

“Reset” can mean restoring content, recreating the subsite or launching a replacement. Define which identity, URL and expiry survive. Mutate every seeded resource type, upload an extra file, schedule a job and change plugin settings. After reset, compare with a canonical manifest. Also confirm that caches and browser sessions cannot expose the previous state.

Control time without waiting in real time

Use short test lifetimes or an injectable clock in non-production environments. Assert behavior immediately before and after the deadline. Extending a session must update the authoritative deadline once; two concurrent extensions must follow a documented rule. The countdown display may drift, but the server must reject actions after expiry.

Prove deletion at every storage layer

Run the named cleanup event and poll with a bounded timeout. Confirm the site is absent from the Multisite site list, its tables and site meta are removed, its upload prefix is gone, and its dedicated user has no remaining membership or record. Check session and token tables, object cache and queued jobs. Treat “already absent” as a safe retry result.

Inject operational failures

  • Disable the cleanup worker for longer than one session lifetime.
  • Terminate it midway through deletion and rerun.
  • Make storage deletion fail while database deletion succeeds.
  • Hold a cleanup lock past its expected lifetime.
  • Restore an older database backup that resurrects expired sessions.
  • Run two workers against the same session.

Each test needs an alert, a recoverable state and a reconciliation result. This is where most “happy path” demo checks fail.

Keep a compact release gate

Run the full suite when WordPress core, the sandbox manager, the demonstrated plugin, its dependencies, PHP or hosting configuration changes. Block release on isolation, token replay, authorization, reset mismatch, cleanup residue or missing monitoring. Store run ID, versions, timings and evidence—not visitor data.

Design a production canary

A low-frequency synthetic launch can reveal DNS, TLS, scheduler and storage failures that staging cannot reproduce. Give the canary an unmistakable marker, never real credentials, and a strict resource quota. It should launch, log in, perform one harmless plugin action, expire and confirm deletion. Alert only after bounded retries and ensure the canary itself cannot build a backlog.

Record evidence that supports debugging

For each state transition, capture a correlation ID, timestamps, site/user IDs, software versions, attempt count and sanitized error category. Do not log launch tokens, cookies or visitor content. Retain enough history to distinguish a slow cleanup from a missing one and to compare failure rate before and after a release. A screenshot of the final page cannot provide that evidence.

Rollback and recovery

Before changing lifecycle code, back up the network database and relevant storage and verify restore in staging. If a release fails the gate, stop new launches, roll back the plugin/configuration, revoke temporary access and run reconciliation in report-only mode. Repair confirmed orphans in small batches, then re-enable launching only after a complete canary finishes cleanly.

Write lifecycle invariants

Define what must always be true: one sandbox has one identity and generation; visitors cannot access siblings; expired sessions cannot mutate state; reset removes prior changes; cleanup is idempotent; and verified deletion leaves no in-scope residue. Tests should assert these properties, not only button text.

Keep invariants versioned with the demonstrated product and infrastructure.

Build deterministic starter fixtures

Create known posts, users, options, files, custom-table rows, queues and mock external records tagged to the sandbox. Include one item in every storage layer. Hash or otherwise identify fixtures so reset and cleanup can be reconciled exactly.

Use synthetic data and never clone production customers into a public demo.

Test provisioning as a transaction

Inject failure after site creation, role setup, dependency activation, content import, routing and token creation. Each retry must resume or compensate without producing duplicate sites or reusable credentials. Visitors should never enter an environment falsely marked ready.

Record state, owner and error for operator recovery.

Verify DNS, TLS and routing

Request the assigned host or path externally, validate certificate coverage, redirects, cookie scope and canonical URL. Wildcard DNS can remove propagation delay but still needs routing and certificate renewal tests. Path-based environments require strict site and cache keys.

A database row alone is not a successful provision.

Test launch-token consumption

Send two simultaneous redemption requests and assert only one succeeds. Replay from another browser, after expiry and after reset. Confirm logs, analytics and referrers never contain the raw token, and the final browser URL is clean.

Check session rotation and intended role after automatic login.

Test authorization by direct endpoints

Enumerate admin, REST, AJAX, upload and plugin-specific actions. Call them anonymously, as the temporary user, as a sibling sandbox and after expiry. Change resource and blog identifiers. Expected denial must occur server-side even if the UI hides the action.

Keep administrator-only test credentials outside the demo and automated artifacts.

Test outbound containment

Attempt email through core and plugin-specific providers, and HTTP toward allowed mock, blocked public, loopback, private and link-local destinations. Follow redirects in tests to expose server-side request forgery gaps. Confirm blocks are logged safely and do not silence platform alerts.

Use mocks so no real messages, charges or external mutations occur.

Exercise the allowed product journey

Install or activate only declared dependencies, perform the main demo tasks, upload bounded media, save settings and view results. Assert the user can complete the promised experience without excessive capability. Record errors, latency and resource use.

A secure sandbox that cannot demonstrate the product fails its contract.

Test reset as a new generation

Create changes in every layer, start a background job, open two sessions and trigger reset. Assert starter fixtures return, visitor data disappears, stale sessions/jobs cannot write, caches are isolated and the generation identifier changes.

Repeat reset to prove idempotency and interruption recovery.

Control time in tests

Inject or abstract the authoritative clock where the system supports it; otherwise set short safe test lifetimes in an isolated environment. Test warning boundary, expiry, request crossing expiry, scheduler delay and clock/timezone edge. Do not wait for production-length windows in every release run.

Confirm browser countdown is presentation only and server authorization owns the decision.

Test cleanup across storage layers

After expiry, reconcile site tables, users/memberships, posts/meta, files, object versions, caches, queues, routes and mock external records. “Delete returned success” is insufficient. Preserve a tombstone and resource counts.

Run cleanup twice; the second pass should be safe and report nothing remaining.

Inject scheduler failures

Pause WP-Cron or the system scheduler, allow sandboxes to expire and confirm access is still revoked. Resume and measure backlog drain. Invoke two cleanup workers concurrently and verify atomic ownership.

Alert on oldest overdue item and cleanup capacity, not just scheduled-event presence.

Inject database and filesystem failures

Simulate a deadlock, unavailable table, read-only directory, full temporary storage and missing file. The lifecycle should move to retry or quarantine with a clear reason, retain its manifest and avoid deleting identity too early.

Repair the dependency and prove restart from the checkpoint.

Inject object-store and network failures

Return throttling, timeout, permission denial and partial deletion. Retry only transient classes with capped backoff. Quarantine permanent configuration errors. Verify no shared prefix is deleted and billed versions are reported honestly.

Use local mocks or isolated test buckets, not production objects.

Test capacity and admission

Launch concurrently until the configured safe limit. Confirm excess requests queue or reject before provisioning, cleanup and administrators retain reserved resources, and retry messaging is accurate. Mix active sessions, resets and expiry rather than testing launch alone.

Stop at defined database, memory, queue and storage thresholds.

Test Multisite identity semantics

Give a synthetic user membership in two test subsites and expire one. Assert only intended membership/content is removed and the network user remains when policy requires. Test site deletion, user deletion and reassignment separately.

Never run identity lifecycle tests against real network users.

Verify observability

Each transition should emit sandbox ID, generation, prior/new state, duration, safe error class and owner without tokens or personal content. Correlate provisioning, access, reset and cleanup. Force notification failure and confirm it is visible.

Dashboards must distinguish active, expired, cleaning, quarantined and verified-deleted.

Build a release gate

SuiteRelease condition
ProvisionTransactional and external route ready
AccessSingle-use token and tenant authorization pass
ContainmentEmail, HTTP, file and cache boundaries pass
ResetAll fixtures restored and stale work rejected
ExpiryAccess denied independent of cleanup
CleanupAll layers reconcile and rerun safely

Design a production canary

At a safe frequency, launch a synthetic sandbox, verify login and a harmless product action, expire it and confirm cleanup within objective. Use dedicated identifiers and exclude canaries from marketing analytics. Do not grant wider rights than public visitors.

Alert only on failure or meaningful regression and prevent overlapping canaries.

Preserve evidence and privacy

Store state timelines, counts, safe errors and screenshots of synthetic data. Redact tokens, cookies, paths and credentials. Define retention and access. A failure artifact should support debugging without becoming a way into the environment.

Delete temporary exports and test media after verification.

Run rollback and recovery drills

Roll back the plugin/configuration while active test sandboxes exist, then verify their access, expiry and cleanup remain defined. Restore a cleanup manifest from backup and finish deletion. Test manual quarantine release with approval and audit.

A release is not safe if rollback strands environments that the new version created.

Worked case: reset leaves an old queue job

A visitor starts an import and resets immediately. Starter content returns, but the old job later writes products into the new session. Page-only assertions passed while generation isolation failed.

The system tags jobs with sandbox generation and rechecks current state before commit. The lifecycle test now holds the worker until after reset and proves the stale write is rejected.

Worked case: expiry waits for cron

A low-traffic demo has no request to trigger WP-Cron. The countdown ends, but an open browser can keep saving because authorization checks only whether the site was deleted. The test pauses the scheduler and exposes the gap.

Expiry becomes a server-side access boundary; cleanup remains asynchronous and resumes later.

Definition of done

All lifecycle invariants pass under normal, duplicate and interrupted execution; direct endpoints enforce tenant and expiry boundaries; reset rejects stale generations; cleanup reconciles every layer and reruns safely; capacity admission preserves recovery; rollback handles existing sandboxes; and a production canary detects regression without exposing data or credentials.

Test browser cache and back navigation

After expiry and reset, use the back button, restore a suspended tab and request cached pages. Sensitive admin content must not reappear as usable state, and actions must be denied server-side. Set appropriate private cache headers for authenticated responses.

Test service workers and application caches where present.

Test concurrent reset and expiry

Trigger reset near the expiry boundary and send duplicate requests. One state transition must own the result; no replacement generation should inherit a cleanup intended for the old one. Stable generation IDs make the expected behavior assertable.

Repeat with a running background job and file upload.

Test dependency upgrades

Provision with the previous and candidate plugin versions, exercise the same journey and clean both. Compare capabilities, endpoints, tables, files and outbound calls. A dependency update can expand the lifecycle surface without changing Sandbox Manager.

Block release until the inventory and containment tests are updated.

Verify resource accounting

Capture database, files, object versions, caches and jobs before provision, after use and after verified cleanup. Explain delayed physical reclamation. The test should fail when a tagged fixture remains, even if the public site disappeared.

Use the accounting result in capacity regression.

Test manual operator actions

Extend, expire, reset, quarantine, retry and delete through approved tools. Verify capability, nonce, audit log and idempotency. Attempt each as a temporary user and confirm denial.

Operator convenience must not bypass state invariants or conceal partial cleanup.

Review canary noise and safety

A canary should use synthetic identity, bounded resources and mocked side effects. Deduplicate alerts until state changes and archive successful detailed logs according to retention. Failed canary cleanup must enter the same visible recovery path as real sandboxes.

Periodically prove the canary itself cannot overlap or exhaust capacity.

Publish a release evidence summary

Record versions, environment, fixture manifest, suites passed, injected failures, capacity mix, known exclusions, reviewer and rollback. Link detailed protected logs without copying secrets into the release note.

This artifact lets operators distinguish a newly introduced failure from an infrastructure change and repeat the exact gate.

Test accessibility of the demo lifecycle

Launch, countdown, warning, reset, expiry and error states must work by keyboard and assistive technology. Focus should move predictably after automatic login or reset, and time limits need accessible notice and extension behavior where offered.

Do not rely on color, animation or a disappearing countdown as the only lifecycle signal.

Test multiple browsers and devices

Exercise supported browsers, mobile layout, private browsing and cookie restrictions. Automatic login and routing can behave differently under tracking prevention. Record the supported matrix and fail with useful guidance rather than looping redirects.

Security boundaries remain server-side regardless of browser behavior.

Validate error messages

Each failed transition should tell the visitor what can be done without exposing paths, queries, site IDs or stack traces. Operators need a correlation identifier and safe error class. Test unauthorized, expired, capacity-full and dependency-failure responses.

Ensure errors themselves are not cached across visitors.

Test cleanup after abnormal visitor behavior

Close the browser mid-upload, start several jobs, abandon an import and leave a transaction incomplete. Expiry and cleanup must still revoke access, cancel or reject stale work and reconcile partial files.

Use bounded synthetic payloads so tests do not become denial-of-service events.

Verify monitoring during failure

Disable one telemetry destination or fill a test log quota. The platform should preserve lifecycle safety and surface monitoring degradation through a separate route. Do not let logging failure roll back successful authorization revocation.

Keep local bounded evidence until the external system recovers.

Maintain the test suite

Review fixtures and routes after every demonstrated-plugin or infrastructure change. Remove obsolete assertions and add new storage, endpoint or dependency layers. Flaky tests should be investigated rather than retried until green.

Assign suite ownership and keep runtime short enough for every release, with deeper failure drills on a scheduled cadence.

Close each release with one clean provision-to-deletion run through the actual scheduler and routing path. This final integration check complements isolated tests and proves that the supported environment can create, use, expire and fully reconcile a synthetic sandbox without manual intervention.

Retain the final canary’s state timeline, safe resource counts and installed versions as the release baseline. Do not retain its token, cookie or synthetic upload longer than necessary. On the next release, compare transition duration and residual checks with this baseline and investigate drift before widening concurrency or publishing new product promises.

Add one test in which the canary runner crashes after each major transition. The next invocation should discover authoritative state, acquire ownership safely and continue or compensate without duplicating the sandbox. This proves persistence rather than success inside one uninterrupted process.

Review failed assertions by invariant and resource layer. A flaky timing retry must not conceal a cross-tenant read, post-expiry write or leftover object. Security and cleanup invariants remain release blockers until the cause is understood and the regression reliably passes.

How WPStack Sandbox Manager fits

WPStack Sandbox Manager 0.3.2 is described as providing per-visitor Multisite demos, one-time automatic login, controlled extensions, immediate expiry/new-test controls, timed cleanup, launch limits, outbound email/HTTP blocking and recent-session visibility. Those behaviors map directly to the lifecycle test matrix.

Do not substitute claims for verification. It is self-hosted and requires Multisite, so scheduler behavior, storage, DNS, SSL and infrastructure failures are environment-specific. Test the installed version with the actual product and dependencies.

Related WPStack guides

Frequently asked questions

Is a successful demo launch enough for a smoke test?

No. It misses replay, authorization, reset, expiry, deletion and reconciliation failures that can create security or capacity problems.

How do I test WP-Cron cleanup reliably?

Run the named event through WP-CLI in staging, record its output, and independently verify resource absence.

Should tests query the database?

Use supported APIs for behavior, plus read-only inventory checks where needed to prove no tables or records remain.

What should happen after partial deletion?

The session should remain visibly incomplete, retry idempotently, and be found by reconciliation—not be marked successfully deleted.

How often should the full lifecycle suite run?

At every relevant release or infrastructure change, with a smaller scheduled canary if the public demo is business-critical.

References