Embedded Go Server
Simfra can run in-process inside Go tests. No Docker, no external process, no port conflicts. Each test gets its own server instance with complete isolation.
Prerequisites
- Go 1.21+
github.com/simfra-dev/simfraadded as a dependency in your Go module
Basic Usage
package myapp_test
import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/sqs"
simfra "github.com/simfra-dev/simfra/pkg/server"
sqssvc "github.com/simfra-dev/simfra/internal/services/sqs"
)
func TestMyFeature(t *testing.T) {
server := simfra.NewServer(sqssvc.New(nil, nil, nil))
endpoint, cleanup := server.Start()
defer cleanup()
// Configure AWS SDK
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithRegion("us-east-1"),
config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(
"AKIAIOSFODNN7EXAMPLE",
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"",
)),
)
if err != nil {
t.Fatal(err)
}
client := sqs.NewFromConfig(cfg, func(o *sqs.Options) {
o.BaseEndpoint = aws.String(endpoint)
})
// Use the client normally
result, err := client.CreateQueue(context.TODO(), &sqs.CreateQueueInput{
QueueName: aws.String("test-queue"),
})
if err != nil {
t.Fatal(err)
}
t.Logf("Queue URL: %s", *result.QueueUrl)
}
API
NewServer
server := simfra.NewServer(services ...services.Service)
Creates a server with only the services you need. Each service constructor accepts optional dependencies (persistence DB, registry, etc.) - pass nil to use defaults.
WithDataDir
server := simfra.NewServer(sqssvc.New(nil, nil, nil)).WithDataDir("/tmp/simfra-test")
Enables SQLite persistence. Resources survive across Start/cleanup cycles if you reuse the same directory. Useful for testing restart behavior.
Start
endpoint, cleanup := server.Start()
defer cleanup()
Starts the server on a random available port. Returns the endpoint URL (e.g., http://127.0.0.1:54321) and a cleanup function that stops the server and closes the database.
StartOnPort
endpoint, cleanup := server.StartOnPort(4599)
Starts on a specific port. Panics if the port is already in use.
CreateAccount
account, err := server.CreateAccount("123456789012")
Creates an additional account programmatically. The default account (000000000000) is created automatically on startup with the standard test credentials.
DB
db := server.DB()
Returns the persistence database, or nil if persistence is not enabled.
AccountRegistry
registry := server.AccountRegistry()
Returns the account registry for advanced account management.
CAManager
ca := server.CAManager()
Returns the CA manager for TLS certificate operations.
Multiple Services
Register multiple services to test cross-service interactions:
import (
snssvc "github.com/simfra-dev/simfra/internal/services/sns"
sqssvc "github.com/simfra-dev/simfra/internal/services/sqs"
iamsvc "github.com/simfra-dev/simfra/internal/services/iam"
)
func TestCrossService(t *testing.T) {
server := simfra.NewServer(
sqssvc.New(nil, nil, nil),
snssvc.New(nil, nil),
iamsvc.New(nil),
)
endpoint, cleanup := server.Start()
defer cleanup()
// SNS subscriptions to SQS queues work
// IAM policy evaluation works
// ...
}
Test Isolation
Each NewServer + Start call creates a completely isolated instance:
- Separate in-memory stores
- Separate account registry
- Separate port
- No shared state between tests
This means tests can run in parallel without interference:
func TestA(t *testing.T) {
t.Parallel()
endpoint, cleanup := simfra.NewServer(sqssvc.New(nil, nil, nil)).Start()
defer cleanup()
// ...
}
func TestB(t *testing.T) {
t.Parallel()
endpoint, cleanup := simfra.NewServer(sqssvc.New(nil, nil, nil)).Start()
defer cleanup()
// ...
}
When to Use the Embedded Server
Use the embedded server when:
- Testing application logic that calls AWS APIs
- Running unit/integration tests in CI without Docker
- You need fast startup (milliseconds, not seconds)
- You want test isolation without port management
Use the standalone process when:
- You need Docker-backed services (CodeBuild, ECS, RDS, Lambda)
- You are testing Terraform modules
- You need persistence across test runs
- You want to interact manually via the AWS CLI
Next Steps
- Testing Patterns - patterns for testing Terraform modules against Simfra
- SDK Configuration - configure AWS SDKs in every major language