End-to-end tests for the httpSMS API. The suite runs the API and its data stores in Docker, keeps the existing Firebase/WireMock coverage, and adds a standard-library-only HTTPS adapter emulator for URL-backed phone gateways.
┌──────────────────┐
│ API (Go) │
│ Port 8000 │
└───────┬──────────┘
│
FCM HTTP │ HTTPS callbacks
┌──────────────────┐ │ ┌──────────────────────┐
│ WireMock │◀──────┘ │ Adapter emulator │
│ Port 8080 │ │ HTTPS callback :9091│
└──────────────────┘ │ HTTP control :9092│
└──────────┬───────────┘
│ phone API calls
└──────────▶ API
┌──────────────────┐ HTTP ┌────────────────────────────┐
│ Test runner │───────────────────▶│ API, WireMock, and adapter │
│ Go test on host │ │ control endpoints │
└──────────────────┘ └────────────────────────────┘
Data stores: CockroachDB, Redis, and MongoDB.
| Component | Description |
|---|---|
| API | The httpSMS Go API server |
| WireMock | Existing fake Firebase and webhook endpoints |
| Adapter emulator | HTTPS URL-backed phone gateway with an HTTP-only host control API |
| CockroachDB | Relational database for API data |
| Redis | Cache and local event queue backend |
| MongoDB | Heartbeat and contact backend |
| Seed | One-shot container that inserts integration users and API keys |
| Test runner | Go tests running on the host |
- Existing FCM flow: the API sends Firebase-compatible requests to WireMock. Existing tests fetch outstanding messages and submit phone events without changing their transport.
- URL-backed outgoing flow: the API posts an FCM-compatible envelope to
https://adapter-emulator:9091/notifications/{gatewayID}. The adapter uses its registered phone API key to fetch the outstanding message and postSENTfollowed byDELIVERED. - URL-backed incoming flow: the test calls the adapter control API on
host port
9092; the adapter posts/v1/messages/receiveas the registered phone. - Heartbeat wake-up: the test dispatches
phone.heartbeat.missedthrough/v1/events. The API sends an HTTPS callback containingKEY_HEARTBEAT_ID, and the adapter posts/v1/heartbeats.
The HTTPS endpoint uses a two-day throwaway CA and server certificate with the
DNS SAN adapter-emulator. The API container trusts only that generated CA via
SSL_CERT_FILE; HTTPS verification is never bypassed. The notification sender
uses the standard OpenTelemetry-instrumented Go HTTP transport.
- Existing encrypted send/receive phone scenarios through WireMock
- Existing rate-limit, webhook, contacts, bulk, and thread scenarios
- URL-backed outgoing message reaches
delivered - URL-backed incoming message reaches
received - URL-backed heartbeat callback stores a heartbeat
- Adapter callback notification IDs are deduplicated in memory
- HTTPS certificate trust is exercised
On Windows, the scripts can be run with Git Bash, for example
C:\Program Files\Git\bin\bash.exe.
Run both scripts before starting Docker:
cd tests
bash generate-firebase-credentials.sh firebase-credentials.json
bash generate-adapter-certificates.sh certs
export FIREBASE_CREDENTIALS=$(jq -c . firebase-credentials.json)The generated Firebase credential and the complete certs/ directory are
ignored by Git.
docker compose up -d --build --wait
docker compose wait seed
sleep 2go test -v -timeout 300s ./...docker compose down -vcd tests && \
bash generate-firebase-credentials.sh firebase-credentials.json && \
bash generate-adapter-certificates.sh certs && \
export FIREBASE_CREDENTIALS=$(jq -c . firebase-credentials.json) && \
docker compose up -d --build --wait && \
docker compose wait seed && \
sleep 2 && \
go test -v -timeout 300s ./... ; \
docker compose down -v.github/workflows/api.yml generates both the fake Firebase credential and
the adapter CA/server certificate before building the Compose stack. The
workflow runs API handler integration tests and this complete host-side suite,
collects service logs on failure, and always tears the stack down.
| Entity | Value |
|---|---|
| User API key | test-user-api-key |
| System API key | system-user-api-key |
| User ID | test-user-id |
| System user ID | system-user-id |
Adapter tests create a unique gateway UUID, phone number, phone API key, and
callback path per test. See seed.sql for shared seed data.
tests/
├── adapter-emulator/
│ ├── Dockerfile
│ ├── go.mod
│ ├── main.go
│ ├── emulator.go
│ ├── api_client.go
│ ├── notification_handler.go
│ ├── control_handler.go
│ └── emulator_test.go
├── wiremock/
│ └── mappings/
├── adapter_integration_test.go
├── integration_test.go
├── helpers_test.go
├── docker-compose.yml
├── .env.test
├── seed.sql
├── generate-firebase-credentials.sh
├── generate-adapter-certificates.sh
├── go.mod
└── go.sum
docker compose logs --tail 200 api adapter-emulatorConfirm tests/certs/ca.pem, server.pem, and server-key.pem exist. TLS
errors should be fixed by regenerating certificates; do not disable HTTPS
verification.
docker compose logs --tail 200 api adapter-emulatorAdapter logs should show callback receipt, the outstanding-message fetch,
SENT, and DELIVERED. Confirm SSL_CERT_FILE=/adapter-certs/ca.pem is
present in the API container.
Adapter logs should show the control request followed by a call to
/v1/messages/receive. The gateway registration contains the per-test phone
number and phone API key.
API logs should show phone.heartbeat.missed. Adapter logs should show
KEY_HEARTBEAT_ID followed by a successful heartbeat POST.
docker compose logs --tail 200 api wiremockKeep FCM_ENDPOINT=http://wiremock:8080; the adapter service does not replace
or weaken the WireMock phone tests.
docker compose logs seedIf a relation does not exist, inspect API migration/startup logs before increasing health-check timing.