| name | run-local-e2e-test |
| description | Run a complete local end-to-end test using the LXD provider to verify a feature, fix, or change works as expected from the user's perspective. Covers creating an environment config, provisioning a VM, deploying the tracker, verifying it works, and cleaning up. Use when manually testing changes, validating a new feature locally, running a full deployment smoke test, or checking that the deployer works end-to-end. Triggers on "local e2e", "manual e2e test", "test my changes locally", "run deployer end-to-end", "smoke test", "test on LXD", "verify feature works", or "full deployment test". |
| metadata | {"author":"torrust","version":"1.0"} |
Run Local E2E Test (LXD Provider)
This skill walks you through a complete manual end-to-end test of the deployer using a local LXD VM. Use it whenever you want to verify that a feature, fix, or change works as an end-user would experience it.
When to Use This Skill
- After implementing a new feature — verify the full workflow works
- After fixing a bug — confirm the fix in a real deployment
- Before opening a PR — smoke-test your changes locally
- Investigating a user-reported issue — reproduce it end-to-end
Prerequisites
cargo run -p torrust-tracker-deployer-dependency-installer --bin dependency-installer -- check
cargo run -p torrust-tracker-deployer-dependency-installer --bin dependency-installer -- install
Note: cargo run --bin dependency-installer does not work from the workspace root because the binary lives in a sub-package. Always use -p torrust-tracker-deployer-dependency-installer.
Complete Workflow
Step 1: Create the Environment Config
cargo run -- create template --provider lxd envs/my-local-test.json
The generated template contains three REPLACE_WITH_* placeholders that must be filled before proceeding:
| Placeholder | Example value |
|---|
REPLACE_WITH_ENVIRONMENT_NAME | my-local-test |
REPLACE_WITH_SSH_PRIVATE_KEY_ABSOLUTE_PATH | /absolute/path/to/repo/fixtures/testing_rsa |
REPLACE_WITH_SSH_PUBLIC_KEY_ABSOLUTE_PATH | /absolute/path/to/repo/fixtures/testing_rsa.pub |
REPLACE_WITH_LXD_PROFILE_NAME | torrust-profile-my-local-test |
Use absolute paths for SSH keys. The fixtures/testing_rsa key pair is ready to use for local testing. The profile name must be unique per environment.
Step 2: Create Environment
cargo run -- create environment --env-file envs/my-local-test.json
Creates data/my-local-test/ and build/my-local-test/.
Step 3: Provision VM (~30–90s)
cargo run -- provision my-local-test --log-output file-and-stderr
Creates the LXD profile and VM, waits for SSH and cloud-init to complete. The command prints the instance IP and an SSH connection string on success.
export INSTANCE_IP=$(cargo run -- show my-local-test --output-format json 2>/dev/null | jq -r '.infrastructure.instance_ip')
echo "VM IP: $INSTANCE_IP"
Step 4: Configure Software (~40–60s)
cargo run -- configure my-local-test
Installs Docker and Docker Compose on the VM.
export INSTANCE_IP=$(cargo run -- show my-local-test --output-format json 2>/dev/null | jq -r '.infrastructure.instance_ip')
ssh -i fixtures/testing_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
torrust@$INSTANCE_IP "docker --version && docker compose version"
Step 5: Release (~7–10s)
cargo run -- release my-local-test
Pulls the tracker Docker image and prepares the runtime environment.
Step 6: Run Tracker (~10–15s)
cargo run -- run my-local-test
Starts the tracker container and waits for health checks. On success the command prints all service URLs (UDP, HTTP tracker, API, Grafana) — no need to run show just to find them.
Step 7: Test (~5–15s)
cargo run -- test my-local-test
Runs automated health checks against the running deployment (HTTP tracker, HTTP API, health endpoints). A good first gate before doing any manual verification.
Step 8: Verify (manual)
What to verify depends on what you are testing. Refer to the relevant guide in docs/e2e-testing/manual/:
Step 9: Clean Up
cargo run -- destroy my-local-test
cargo run -- purge my-local-test --force
destroy removes the infrastructure (LXD VM, profile, OpenTofu state) but keeps the local environment data. Its output already reminds you to run purge. purge removes the remaining data/ and build/ directories so the environment name can be reused. Use --force to skip the interactive confirmation prompt.
cargo run -- show my-local-test; echo "exit: $?"
Quick Reference: Show Command
Use the show command instead of parsing internal state files:
cargo run -- show <env-name>
cargo run -- show <env-name> --output-format json
export INSTANCE_IP=$(cargo run -- show <env-name> --output-format json 2>/dev/null | jq -r '.infrastructure.instance_ip')
cargo run -- show <env-name> --output-format json | jq -r '.state'
Recovery After Interruption
If a command is interrupted mid-run:
cargo run -- show my-local-test --output-format json 2>/dev/null | jq -r '.state'
Provisioning (interrupted): destroy and retry from Step 3
Configuring (interrupted): re-run configure command
Releasing / Running (interrupted): re-run release or run
Destroying (interrupted): re-run destroy, then purge --force
lxc delete torrust-tracker-vm-my-local-test --force 2>/dev/null
lxc profile delete torrust-profile-my-local-test 2>/dev/null
rm -rf data/my-local-test build/my-local-test
Choosing a Config for Different Test Scenarios
| Scenario | Config to use / modify |
|---|
| Basic smoke test | SQLite (default template) |
| MySQL integration | Add "driver": "mysql" + MySQL fields in core.database |
| Monitoring stack | Add prometheus + grafana sections |
| Backup feature | Add backup section |
| HTTPS/TLS | Add https section + set bind_address to HTTPS ports |
Further Reference