test: add FastAPI mock backend + Kind-based e2e harness#209
Open
test: add FastAPI mock backend + Kind-based e2e harness#209
Conversation
Lets the local VPC agent be tested against a stand-in for the DrDroid
cloud backend without hitting prod. The mock issues its own bearer
token, records every inbound request as JSONL, and lets tests seed
connection-test + playbook-task scenarios via an admin API.
What's in mock_backend/:
- app.py / storage.py: FastAPI service implementing the agent's wire
contract — GET/POST /connectors/proxy/ping, /register,
/connector/connection/{tests,results}, /connector/metadata/register,
/playbooks-engine/proxy/execution/{tasks,results}.
- Dockerfile + k8s/manifests.yaml: tiny python:3.12-alpine image
deployed as a Service in the drdroid namespace; agent pods reach it
over cluster DNS at drd-vpc-agent-mock.drdroid.svc.cluster.local:8080.
- deploy_kind.sh: one-shot orchestrator. Ensures Kind cluster, builds
(or auto-reuses) the agent image, mints a token, applies the
credentials-secret the helm chart needs, deploys the agent via helm,
seeds scenarios, runs e2e.py. Self-contained — does not depend on
the per-user gitignored deploy_local.sh.
- e2e.py: validator. Asserts startup ping, heartbeat, queue drain,
result round-trip, and ASSET_REFRESH metadata batches. For each
kubectl scenario it parses the agent's output, asserts stable
cluster invariants are present, and (when host kubectl is
available) diffs the set of metadata.name values against a host
snapshot.
- scenarios/default.json: 1 ASSET_REFRESH + 4 real kubectl tasks
(get pods/svc/namespaces/events on drdroid). Connection-tests are
filtered by what's in credentials/secrets.yaml so empty configs
don't trigger spurious failures.
Project-scoped slash command at .claude/commands/test-vpc-agent.md so
/test-vpc-agent runs the full loop. .claude/settings.local.json added
to .gitignore.
Validated end-to-end on Kind: 20/20 checks pass, including exact
host-vs-agent name-set match for pods, services, and namespaces.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mock_backend/— a FastAPI service that simulates the DrDroid cloud backend so the local VPC agent can be tested in isolation. Issues its own bearer token, records every inbound call as JSONL, and exposes an admin API for seeding connection-test + playbook-task scenarios.mock_backend/deploy_kind.shbrings up Kind, builds (or auto-reuses) the agent image, deploys both the mock and the real agent via helm pointed at the in-cluster mock service, seeds scenarios, and runs the validator. Self-contained — no dependency on the per-user gitignoreddeploy_local.sh.e2e.pyvalidates more than transport: it pulls the agent'skubectl getoutput from the recordings, asserts cluster invariants, and (when hostkubectlis on PATH) diffs the set ofmetadata.namevalues against a host snapshot for ground-truth verification./test-vpc-agentat.claude/commands/test-vpc-agent.mdso the loop is one keystroke from any session.What's actually tested
Default scenarios (
mock_backend/scenarios/default.json):ASSET_REFRESHtask on the native Kubernetes connector.kubectltasks:get pods -n drdroid,get svc -n drdroid,get namespaces,get events -n drdroid.Validator checks (20/20 passing on Kind):
GET /connectors/proxy/ping, heartbeatPOST /connectors/proxy/ping, connection-test poll, playbook-task poll, result round-trip — every endpoint in the agent's wire contract.ASSET_REFRESHproduces ≥1 batch at/connectors/proxy/connector/metadata/register.kubectltask: output is parseable JSON, deployment-stable items are present (mock pod inget pods, mock service inget svc,drdroidns inget namespaces, events non-empty), and the agent's name-set matches the host'skubectlsnapshot exactly.Usage
You don't bring a token — the mock issues one and the script wires it into helm. Auto-reuse: when
drd-vpc-agent:local-<commit>already exists locally, the alpine 20-min build is skipped and a full test loop is ~30s.Notable nits handled
helm/credentials-secret.yamllives at the chart root (not undertemplates/) sohelm installdoesn't apply it.deploy_kind.shcreates the secret fromcredentials/secrets.yaml(or an empty placeholder) before the helm step — without this, agent pods hang inInit:0/1withFailedMount.credentials/secrets.yaml(the agent silently no-ops requests for unknown connectors), so empty local setups still hit all-green..claude/settings.local.jsonadded to.gitignore(per-user permissions;.claude/commands/stays tracked).Test plan
./mock_backend/deploy_kind.sh --reuse-imagefrom a clean Kind state — 20/20 checks pass.kubectl get pods/svc/namespaces -o jsonmatches the agent's reported name-sets exactly.ASSET_REFRESHproduces 4 metadata batches at/connector/metadata/register.credentials/secrets.yamldoes not cause spurious failures.🤖 Generated with Claude Code