End-to-end integration tests for the httpSMS API. These tests validate the complete SMS lifecycle by running the full application stack in Docker alongside a phone emulator service.
┌──────────────┐ HTTP ┌──────────────┐
│ Test Runner │─────────────▶│ API (Go) │
│ (Go test) │ │ Port 8000 │
└──────────────┘ └──────┬───────┘
│
FCM Push │ Events
(HTTP) │ (HTTP)
▼
┌──────────────┐
│ Emulator │
│ (Fiber v3) │
│ Port 9090 │
└──────────────┘
│
┌──────┴───────┐
│ PostgreSQL │ │ Redis │
│ Port 5435 │ │ Port 6379 │
└──────────────┘ └─────────────┘
| Component | Description |
|---|---|
| API | The httpSMS Go API server running in Docker |
| Emulator | A Fiber v3 Go service that simulates an Android phone |
| PostgreSQL | Database for the API |
| Redis | Cache and queue backend |
| Seed | One-shot container that seeds test data into PostgreSQL |
| Test Runner | Go test binary that runs on the host machine |
-
Send SMS flow: Test sends
POST /v1/messages/send→ API pushes FCM notification to emulator → Emulator callsGET /v1/messages/outstanding→ Emulator firesSENTandDELIVEREDevents → Test pollsGET /v1/messages/{id}until status isdelivered -
Receive SMS flow: Test sends
POST /v1/messages/receive(as the phone) → API stores message → Test verifies viaGET /v1/messages/{id}
The API's Firebase SDK is configured (via FCM_ENDPOINT env var) to redirect all FCM HTTP requests to the emulator instead of Google's servers. The emulator serves:
/token— Fake OAuth2 token endpoint (Firebase SDK requests tokens before sending)/v1/projects/:project/messages:send— Fake FCM push endpoint
- Send SMS E2E — Full send lifecycle: API → FCM push → emulator responds with SENT/DELIVERED events → message reaches
deliveredstatus - Receive SMS E2E — Phone submits received message to API → message is stored and retrievable via GET endpoint
- Docker with Docker Compose
- Go 1.22+
- jq (for Firebase credentials generation)
- OpenSSL (for RSA key generation)
The integration tests use a fake Firebase service account. Generate it with:
cd tests
bash generate-firebase-credentials.shThis creates firebase-credentials.json with a throwaway RSA key (the emulator doesn't validate tokens).
export FIREBASE_CREDENTIALS=$(jq -c . firebase-credentials.json)docker compose up -d --build --waitThis starts PostgreSQL, Redis, the API, and the emulator. The --wait flag blocks until all health checks pass.
docker compose wait seed
sleep 2The seed container inserts test users, phones, and API keys into PostgreSQL after the API has run its GORM migrations.
go test -v -timeout 120s ./...docker compose down -vThe -v flag removes volumes (database data) for a clean slate next run.
cd tests && \
bash generate-firebase-credentials.sh && \
export FIREBASE_CREDENTIALS=$(jq -c . firebase-credentials.json) && \
docker compose up -d --build --wait && \
docker compose wait seed && \
sleep 2 && \
go test -v -timeout 120s ./... ; \
docker compose down -vIntegration tests run automatically via GitHub Actions (.github/workflows/integration-test.yml):
- Trigger: Push to
mainor pull request targetingmain - Flow: Generates credentials → Starts Docker stack → Seeds DB → Runs tests → Collects logs on failure → Tears down
- Gate: Deployment should only proceed if integration tests pass
| Entity | Value |
|---|---|
| User API Key | test-user-api-key |
| Phone API Key | pk_test-phone-api-key |
| Phone Number | +18005550199 |
| Contact Number | +18005550100 |
| User ID | test-user-id |
| Phone ID | a1b2c3d4-e5f6-7890-abcd-ef1234567890 |
See seed.sql for the complete seed data.
tests/
├── docker-compose.yml # Full stack orchestration
├── seed.sql # Database seed data
├── .env.test # API environment variables
├── generate-firebase-credentials.sh # Generates fake Firebase credentials
├── go.mod # Test runner Go module
├── go.sum
├── helpers_test.go # Test utilities (HTTP client, polling)
├── integration_test.go # E2E test cases
└── emulator/ # Phone emulator service
├── Dockerfile
├── go.mod
├── go.sum
├── main.go # Fiber v3 entry point
├── emulator.go # Emulator struct and config
├── token_handler.go # Fake OAuth2 token endpoint
├── fcm_handler.go # Fake FCM push receiver
└── events.go # Event firing logic (SENT/DELIVERED)
Check the API logs:
docker compose logs apiCommon issues:
FIREBASE_CREDENTIALSenv var not set or malformed- PostgreSQL not ready (increase
start_periodin healthcheck)
Check the emulator logs:
docker compose logs emulatorThe emulator should show:
[FCM]— Receiving the push notification[EVENTS]— Fetching outstanding messages and firing events
If no [FCM] entries appear, the API isn't reaching the emulator (check FCM_ENDPOINT in .env.test).
docker compose logs seedIf you see "relation does not exist" errors, the API hasn't finished GORM migrations yet. Increase the API's start_period in docker-compose.yml.
- Add test functions to
integration_test.go(or create new*_test.gofiles) - Use
doRequest()helper for authenticated HTTP calls - Use
pollMessageStatus()to wait for async state changes - Update the test coverage checklist in this README