Skip to main content

Test Architecture

This guide explains the design decisions behind Crawbl's E2E test suite — the 3-user model, auth bypass, feature file layout, and cleanup strategy.

3-User Model

Each test run creates exactly 3 users at suite level. These users are reused across all 73 scenarios:

UserPurpose
primaryMost scenarios — auth, profile, legal, workspaces, chat, agents
frankMulti-user isolation and account deletion tests
graceMulti-user isolation tests

Why 3 Users Instead of Per-Scenario

Each user triggers a UserSwarm custom resource, which provisions a workspace runtime Deployment, Services, and pods. Creating a user per scenario would spawn 73+ Deployments, overwhelming the cluster with hundreds of Kubernetes resources.

The 3-user model caps cluster load at 3 UserSwarms regardless of how many scenarios run.

Auth Bypass (X-E2E-Token)

Tests skip Firebase JWT authentication using the X-E2E-Token header. The flow looks like this:

1
Step 1

Send the E2E headers

The test request includes the shared X-E2E-Token value plus the X-E2E-* identity headers.

2
Step 2

Route through the E2E path

Envoy sends the request through orchestrator-e2e, which has no JWT SecurityPolicy.

3
Step 3

Validate inside the backend

The orchestrator middleware checks CRAWBL_E2E_TOKEN and reads identity from X-E2E-UID, X-E2E-Email, and X-E2E-Name.

4
Step 4

Handle the request normally

Once the principal is attached, the rest of the handler logic runs as usual.

This bypass is disabled in production. The orchestrator checks env != "production" && env != "prod" before accepting E2E tokens. The token itself is stored in AWS Secrets Manager and synced to the cluster via External Secrets Operator.

Feature Files

Feature files live in crawbl-backend/internal/testsuite/e2e/features/ organized into 8 category folders — 30 files, 73 scenarios total:

CategoryFilesScenariosCoverage
auth/49Sign-up, sign-in, logout, deletion, error cases
chat/718Conversations, messages, mentions, agent details, memories
core/510Health, legal, models, uploads, edge cases
integrations/13Tool catalog, agent tools, integration apps
multi_user/26Workspace isolation, cross-user access prevention
profile/25Profile CRUD, FCM tokens, error cases
tools/24Memory (store/recall/forget), web search
workspaces/39Default workspace, first launch, runtime readiness

Step Definition Files

Step definitions are split by responsibility across 14 files:

FileResponsibility
steps_http.goHTTP request construction and execution
steps_assert.goResponse status, body, and JSON assertions
steps_db.goDirect database state verification
steps_user.goUser creation, authentication, lifecycle
steps_state.goValue storage and {{...}} interpolation
steps_auth.goAuth flow steps (sign-up, sign-in, token handling)
steps_chat.goConversation and message steps
steps_workspaces.goWorkspace listing and runtime status steps
steps_agents.goAgent detail, history, and settings steps
steps_profile.goProfile and FCM token steps
steps_legal.goTerms/privacy acceptance steps
steps_tools.goMemory and web search tool steps
steps_integrations.goIntegration catalog and app steps
steps_multi_user.goCross-user isolation and access prevention steps

Async Polling

Agent-side effects (memory writes, tool results, swarm state) are not synchronous. Tests use pollUntil(ctx, fn) to wait for these effects to settle:

  • Polls every 1 second for up to 30 seconds
  • Fails the step if the condition is not met within the timeout
  • Used wherever a test depends on the agent runtime completing work before asserting

3-Layer Cleanup Strategy

Test resources must never accumulate in the cluster. Crawbl uses three independent cleanup layers:

1
Step 1

Suite cleanup

After all scenarios finish, the suite calls DELETE /v1/auth/delete for each of the 3 test users.

2
Step 2

Signal handler cleanup

If the test process gets SIGINT or SIGTERM, RunUntilSignal performs graceful cleanup before exit.

3
Step 3

Reaper CronJob cleanup

A cluster-side reaper runs every 2 minutes and removes stale e2e-* users older than 2 hours along with their workspace runtime resources.

crawbl platform operator reaper --max-age=2h

Summary

LayerTriggerAction
Suite cleanupAll scenarios completeDELETE /v1/auth/delete for all 3 users
Signal handlerSIGINT/SIGTERMGraceful cleanup before exit
Reaper CronJobEvery 2 minutesFinds and removes stale e2e-* users older than 2h

The DELETE /v1/auth/delete handler looks up the user by subject, lists their workspaces, calls runtimeClient.DeleteRuntime(workspaceID) for each, and soft-deletes the user record. The operator finalizer then cleans up all child Kubernetes resources (Deployment, Services).


What's next: CI/CD Pipeline