# Test Environment

## Platform

Three execution contexts — all use **native** Docker for the host CPU (no Rosetta / QEMU emulation).

| Context | Host CPU | Docker platform | How tests/builds run |
|---------|----------|-----------------|----------------------|
| **Local dev** | Apple Silicon Mac (`darwin/arm64`, e.g. M1) | `linux/arm64` | `scripts/run-tests.sh` sets `DOCKER_DEFAULT_PLATFORM=linux/arm64`; compose builds follow the host |
| **CI unit tests** | Woodpecker `platform: arm64` agent (colocated Jetson) | `linux/arm64` | `.woodpecker/01-test.yml` — `dotnet test` in sdk image (arm64-only by suite convention) |
| **CI image build** | Woodpecker `platform: arm64` **or** `amd64` agent | matches agent | `.woodpecker/02-build-push.yml` matrix — same Dockerfile, tags `{branch}-arm` / `{branch}-amd64` |

**Mac M1 rule**: do **not** pin `platform: linux/amd64` in compose files or Dockerfiles. That forces Rosetta/QEMU emulation and logs warnings such as `The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8)`.

**amd64 agent rule**: the remote Woodpecker amd64 agent builds production images natively. Deploy (`suite/_infra/deploy/satellite-provider/`) pulls `${BRANCH}-amd64` — built only on the amd64 agent, not cross-compiled from arm64.

| Surface | Behavior |
|---------|----------|
| `scripts/run-tests.sh` | On `darwin/arm64`, exports `DOCKER_DEFAULT_PLATFORM=linux/arm64` before every `docker run` / `docker compose` |
| `docker-compose.tests.yml` | No `platform:` override — images match the host (arm64 on Mac, amd64 on an amd64 Linux dev box) |
| `docker-compose.yml` (dev / perf) | Same — no arch pin |
| API + integration Dockerfiles | Multi-arch `sdk:10.0` / `aspnet:10.0`; build stage installs Debian `protobuf-compiler` + `PROTOBUF_PROTOC=/usr/bin/protoc` on **arm64** (bundled `Grpc.Tools` `linux_arm64/protoc` segfaults; harmless on amd64) |

Suite CI/agent reference: [`suite/_infra/ci/README.md`](../../../../_infra/ci/README.md) § Agent pools and § Build-push step.

## Infrastructure

| Component | Technology | Configuration |
|-----------|-----------|---------------|
| System Under Test | SatelliteProvider.Api (Docker container) | ASPNETCORE_ENVIRONMENT=Development |
| Database | PostgreSQL 16 (Docker container) | Fresh DB per test run (migrations auto-applied) |
| Test Runner | Custom console app (SatelliteProvider.IntegrationTests) | Docker container on same network |
| Orchestration | docker-compose.tests.yml | Waits for API health before starting tests |
| Perf orchestration | docker-compose.yml + docker-compose.perf.yml | See [containerization.md](../deployment/containerization.md) — host port 5433 conflict playbook |

## Network Topology

```
[Test Runner] --HTTP--> [API :8080] --TCP--> [PostgreSQL :5432]
                              |
                              +--HTTPS--> [Google Maps] (external, real)
```

## External Dependencies

| Dependency | Strategy | Notes |
|------------|----------|-------|
| Google Maps tile server | Real (live) | Integration tests use real downloads; requires GOOGLE_MAPS_API_KEY |
| PostgreSQL | Real (containerized) | Fresh database each run via migrations |
| File system | Real (Docker volume) | ./tiles, ./ready, ./logs mounted |

## Environment Variables

| Variable | Value | Purpose |
|----------|-------|---------|
| API_URL | http://api:8080 | Test runner → API connection |
| ASPNETCORE_ENVIRONMENT | Development | API config mode |
| ConnectionStrings__DefaultConnection | Host=postgres;Port=5432;... | DB connection |
| MapConfig__ApiKey | (from host env) | Google Maps auth |
| GOOGLE_MAPS_API_KEY | (from `.env` or shell env) | Google Maps tile downloads (AZ-487 onward — required for any integration mode) |
| JWT_SECRET | (from `.env` or shell env; ≥ 32 bytes) | HS256 signing key shared by API + test runner (AZ-487); fail-fast at startup if missing |
| JWT_ISSUER | (from `.env` or shell env) | Expected `iss` claim (AZ-494); fail-fast at startup if missing. DEV-ONLY local value: `DEV-ONLY-iss-admin-azaion-local` |
| JWT_AUDIENCE | (from `.env` or shell env) | Expected `aud` claim (AZ-494); fail-fast at startup if missing. DEV-ONLY local value: `DEV-ONLY-aud-satellite-provider` |
| INTEGRATION_TEST_DB_RESET | `enabled` (default) / `skip` (set by `--keep-state`) | AZ-493 reset hook; `enabled` truncates test-table rows on runner start, `skip` preserves them for debugging |

## Test Execution

**Decision**: Docker (no hardware dependencies detected)
**Hardware dependencies found**: None
**Canonical entry point**: `./scripts/run-tests.sh` (Step 0: format check; Step 1: unit tests; Step 2: integration tests via Compose).

**Manual integration command** (matches `run-tests.sh` Step 2):

```bash
docker compose -f docker-compose.tests.yml up --build --abort-on-container-exit --exit-code-from integration-tests
```

`docker-compose.tests.yml` is self-contained (postgres + api + integration-tests on an internal Docker network). Postgres is not published to the host — intentional when host port 5433 is occupied by a sibling stack.

**Performance tests** (Step 15 / `scripts/run-performance-tests.sh`): start the API with the perf overlay when host port 5433 is occupied — `docker compose -f docker-compose.yml -f docker-compose.perf.yml up -d --build`. Details: [containerization.md](../deployment/containerization.md#compose-overlays-dev--test--perf). PT-10 (`DeliverRouteTiles` gRPC stream) runs via `dotnet SatelliteProvider.IntegrationTests --run-pt10` inside the script; host-side default `API_URL=https://localhost:18980` with TLS trust via `./certs/api.crt` (`PERF_CA_CERT` override). Harness knobs:

| Variable | Default | Purpose |
|----------|---------|---------|
| `PERF_REPEAT_COUNT` | 20 | Cold iterations for PT-07/PT-08/PT-10 distribution |
| `PERF_UAV_BATCH_SIZE` | 10 | Items per PT-08 upload batch |
| `PERF_PT10_SLOW_MS` | 50 | Delay between gRPC stream events on the slow-consumer sub-check (PT-10) |
| `PERF_JWT_TOKEN` | (minted in-script) | Pre-minted Bearer token; skips `--mint-only` when set |
| `PERF_CA_CERT` | `$PROJECT_ROOT/certs/api.crt` | TLS trust anchor for host-side perf probes (REST + gRPC) |

See [performance-tests.md](performance-tests.md) § PT-10 for pass thresholds.

| Property | Value |
|----------|-------|
| Execution mode | Sequential (one test at a time) |
| Timeout per test | 15 minutes (HttpClient timeout) |
| Polling interval | 2–3 seconds |
| Max poll attempts | 120–360 (depends on test) |
| Startup wait | 30 retries × 2s = 60s max |
