package test import ( "context" "fmt" "io" "net/http" "testing" "time" "queryorchestration/internal/serviceconfig" "queryorchestration/internal/serviceconfig/objectstore" "github.com/docker/go-connections/nat" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" ) type AWSContainerConfig struct { Container testcontainers.Container ExternalEndpoint string NetworkEndpoint string } type CreateAWSConfig struct { Network *testcontainers.DockerNetwork } type AWSConfigProvider interface { serviceconfig.ConfigProvider objectstore.ConfigProvider } func CreateAWSContainer(t testing.TB, ctx context.Context, cfg AWSConfigProvider, acfg *CreateAWSConfig) (*AWSContainerConfig, func()) { alias := "localstack" port, err := nat.NewPort("tcp", "4566") require.NoError(t, err) req := testcontainers.ContainerRequest{ Image: "localstack/localstack:4.1.0", Env: map[string]string{ "AWS_ACCESS_KEY_ID": cfg.GetAWSKeyID(), "AWS_SECRET_ACCESS_KEY": cfg.GetAWSSecretKey(), "AWS_SESSION_TOKEN": cfg.GetAWSSessionToken(), "AWS_REGION": cfg.GetAWSRegion(), "SERVICES": "s3,sqs,cloudwatch,logs", "SKIP_SSL_CERT_DOWNLOAD": "1", "LOCALSTACK_HOST": alias, "SQS_ENDPOINT_STRATEGY": "path", "EAGER_SERVICE_LOADING": "1", "DEBUG": "1", "LS_LOG": "trace", "SQS_CLOUDWATCH_METRICS_REPORT_INTERVAL": "5", }, ExposedPorts: []string{port.Port()}, WaitingFor: wait.ForAll( wait.ForListeningPort(port), wait.ForLog("Ready."), wait.ForHTTP("/_localstack/health"). WithPort(port). WithStartupTimeout(50*time.Second). WithPollInterval(5*time.Second). WithResponseMatcher(func(body io.Reader) bool { return true }). WithStatusCodeMatcher(func(statusCode int) bool { return statusCode == http.StatusOK }), ), } if acfg.Network != nil { req.Networks = []string{acfg.Network.Name} req.NetworkAliases = map[string][]string{ acfg.Network.Name: {alias}, } } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, }) require.NoError(t, err) host, err := container.Host(ctx) require.NoError(t, err) mappedPort, err := container.MappedPort(ctx, port) require.NoError(t, err) extEndpoint := fmt.Sprintf("http://%s:%s", host, mappedPort.Port()) t.Setenv("AWS_ENDPOINT_URL", extEndpoint) cfg.SetAWSEndpoint(extEndpoint) t.Setenv("AWS_ENDPOINT_URL_SQS", extEndpoint) cfg.SetSQSEndpoint(extEndpoint) t.Setenv("AWS_ENDPOINT_URL_S3", extEndpoint) cfg.SetS3Endpoint(extEndpoint) var endpoint string if acfg.Network != nil { endpoint = fmt.Sprintf("http://%s:%s", alias, port.Port()) cfg.SetAWSEndpoint(endpoint) cfg.SetSQSEndpoint(endpoint) cfg.SetS3Endpoint(endpoint) } return &AWSContainerConfig{ Container: container, ExternalEndpoint: extEndpoint, NetworkEndpoint: endpoint, }, func() { err := container.Terminate(ctx) if err != nil { t.Error(err) } } }