diff --git a/docs/modules/azure.md b/docs/modules/azure.md
index 8260970369..695e0efeb8 100644
--- a/docs/modules/azure.md
+++ b/docs/modules/azure.md
@@ -61,6 +61,12 @@ In example: `Run(context.Background(), "mcr.microsoft.com/azure-storage/azurite:
When starting the Azurite container, you can pass options in a variadic way to configure it.
+#### WithEnabledServices
+
+- Not available until the next release :material-tag: main
+
+The default Azurite container entrypoint runs all three storage services: blob, queue, and table. Use this option to specify the required services for fewer exposed ports and slightly reduced container resources. E.g. `azurite.WithEnabledServices(azurite.BlobService)`.
+
#### WithInMemoryPersistence
- Since :material-tag: v0.36.0
diff --git a/modules/azure/azurite/azurite.go b/modules/azure/azurite/azurite.go
index 9eeabd5a54..83a4530310 100644
--- a/modules/azure/azurite/azurite.go
+++ b/modules/azure/azurite/azurite.go
@@ -33,74 +33,85 @@ type Container struct {
opts options
}
-// Deprecated: Use [azure.BlobServiceURL], [azure.QueueServiceURL], or [azure.TableServiceURL] methods instead.
// ServiceURL returns the URL of the given service
func (c *Container) ServiceURL(ctx context.Context, srv Service) (string, error) {
- return c.serviceURL(ctx, srv)
+ port, err := servicePort(srv)
+ if err != nil {
+ return "", err
+ }
+
+ return c.PortEndpoint(ctx, port, "http")
}
// BlobServiceURL returns the URL of the Blob service
func (c *Container) BlobServiceURL(ctx context.Context) (string, error) {
- return c.serviceURL(ctx, blobService)
+ return c.ServiceURL(ctx, BlobService)
}
// QueueServiceURL returns the URL of the Queue service
func (c *Container) QueueServiceURL(ctx context.Context) (string, error) {
- return c.serviceURL(ctx, queueService)
+ return c.ServiceURL(ctx, QueueService)
}
// TableServiceURL returns the URL of the Table service
func (c *Container) TableServiceURL(ctx context.Context) (string, error) {
- return c.serviceURL(ctx, tableService)
+ return c.ServiceURL(ctx, TableService)
}
-func (c *Container) serviceURL(ctx context.Context, srv service) (string, error) {
- var port nat.Port
+func servicePort(srv Service) (nat.Port, error) {
switch srv {
- case blobService:
- port = BlobPort
- case queueService:
- port = QueuePort
- case tableService:
- port = TablePort
+ case BlobService:
+ return BlobPort, nil
+ case QueueService:
+ return QueuePort, nil
+ case TableService:
+ return TablePort, nil
default:
return "", fmt.Errorf("unknown service: %s", srv)
}
-
- return c.PortEndpoint(ctx, port, "http")
}
// Run creates an instance of the Azurite container type
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
- moduleCmd := []string{}
-
- moduleOpts := []testcontainers.ContainerCustomizer{
- testcontainers.WithEntrypoint("azurite"),
- testcontainers.WithExposedPorts(BlobPort, QueuePort, TablePort),
- }
-
// 1. Gather all config options (defaults and then apply provided options)
settings := defaultOptions()
+ for _, opt := range opts {
+ if o, ok := opt.(Option); ok {
+ if err := o(&settings); err != nil {
+ return nil, fmt.Errorf("azurite option: %w", err)
+ }
+ }
+ }
+
+ entrypoint := "azurite"
+ if len(settings.EnabledServices) == 1 && settings.EnabledServices[0] != TableService {
+ // Use azurite-table in future once it matures. Graceful shutdown is currently very slow.
+ entrypoint = fmt.Sprintf("%s-%s", entrypoint, settings.EnabledServices[0])
+ }
+ moduleOpts := []testcontainers.ContainerCustomizer{testcontainers.WithEntrypoint(entrypoint)}
// 2. evaluate the enabled services to apply the right wait strategy and Cmd options
if len(settings.EnabledServices) > 0 {
+ cmd := make([]string, 0, len(settings.EnabledServices))
+ exposedPorts := make([]string, 0, len(settings.EnabledServices))
waitingFor := make([]wait.Strategy, 0, len(settings.EnabledServices))
+
for _, srv := range settings.EnabledServices {
- switch srv {
- case BlobService:
- moduleCmd = append(moduleCmd, "--blobHost", "0.0.0.0")
- waitingFor = append(waitingFor, wait.ForListeningPort(BlobPort))
- case QueueService:
- moduleCmd = append(moduleCmd, "--queueHost", "0.0.0.0")
- waitingFor = append(waitingFor, wait.ForListeningPort(QueuePort))
- case TableService:
- moduleCmd = append(moduleCmd, "--tableHost", "0.0.0.0")
- waitingFor = append(waitingFor, wait.ForListeningPort(TablePort))
+ port, err := servicePort(srv)
+ if err != nil {
+ return nil, err
}
+
+ cmd = append(cmd, fmt.Sprintf("--%sHost", srv), "0.0.0.0", fmt.Sprintf("--%sPort", srv), port.Port())
+ exposedPorts = append(exposedPorts, string(port))
+ waitingFor = append(waitingFor, wait.ForListeningPort(port))
}
- moduleOpts = append(moduleOpts, testcontainers.WithCmd(moduleCmd...))
- moduleOpts = append(moduleOpts, testcontainers.WithWaitStrategy(waitingFor...))
+ moduleOpts = append(moduleOpts,
+ testcontainers.WithCmd(cmd...),
+ testcontainers.WithExposedPorts(exposedPorts...),
+ testcontainers.WithWaitStrategy(waitingFor...),
+ )
}
moduleOpts = append(moduleOpts, opts...)
diff --git a/modules/azure/azurite/azurite_test.go b/modules/azure/azurite/azurite_test.go
index 1809ae767e..37e693bd34 100644
--- a/modules/azure/azurite/azurite_test.go
+++ b/modules/azure/azurite/azurite_test.go
@@ -36,6 +36,38 @@ func TestAzurite_inMemoryPersistence(t *testing.T) {
})
}
+func TestAzurite_enabledServices(t *testing.T) {
+ ctx := context.Background()
+
+ services := []azurite.Service{azurite.BlobService, azurite.QueueService, azurite.TableService}
+ for _, service := range services {
+ t.Run(string(service), func(t *testing.T) {
+ ctr, err := azurite.Run(ctx, "mcr.microsoft.com/azure-storage/azurite:3.33.0", azurite.WithEnabledServices(service))
+ testcontainers.CleanupContainer(t, ctr)
+ require.NoError(t, err)
+
+ for _, srv := range services {
+ _, err = ctr.ServiceURL(ctx, srv)
+ if srv == service {
+ require.NoError(t, err)
+ } else {
+ require.Error(t, err)
+ }
+ }
+ })
+ }
+
+ t.Run("unknown", func(t *testing.T) {
+ _, err := azurite.Run(ctx, "mcr.microsoft.com/azure-storage/azurite:3.33.0", azurite.WithEnabledServices("foo"))
+ require.EqualError(t, err, "azurite option: unknown service: foo")
+ })
+
+ t.Run("duplicate", func(t *testing.T) {
+ _, err := azurite.Run(ctx, "mcr.microsoft.com/azure-storage/azurite:3.33.0", azurite.WithEnabledServices(azurite.BlobService, azurite.BlobService))
+ require.EqualError(t, err, "azurite option: duplicate service: blob")
+ })
+}
+
func TestAzurite_serviceURL(t *testing.T) {
ctx := context.Background()
diff --git a/modules/azure/azurite/examples_test.go b/modules/azure/azurite/examples_test.go
index 9fc8c91f21..842720dfd6 100644
--- a/modules/azure/azurite/examples_test.go
+++ b/modules/azure/azurite/examples_test.go
@@ -57,6 +57,7 @@ func ExampleRun_blobOperations() {
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.33.0",
azurite.WithInMemoryPersistence(64),
+ azurite.WithEnabledServices(azurite.BlobService),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
@@ -198,6 +199,7 @@ func ExampleRun_queueOperations() {
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.28.0",
azurite.WithInMemoryPersistence(64),
+ azurite.WithEnabledServices(azurite.QueueService),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
@@ -292,6 +294,7 @@ func ExampleRun_tableOperations() {
ctx,
"mcr.microsoft.com/azure-storage/azurite:3.28.0",
azurite.WithInMemoryPersistence(64),
+ azurite.WithEnabledServices(azurite.TableService),
)
defer func() {
if err := testcontainers.TerminateContainer(azuriteContainer); err != nil {
diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go
index 7e8d2dc780..1666894c7c 100644
--- a/modules/azure/azurite/options.go
+++ b/modules/azure/azurite/options.go
@@ -8,12 +8,51 @@ import (
type options struct {
// EnabledServices is a list of services that should be enabled
- EnabledServices []service
+ EnabledServices []Service
}
func defaultOptions() options {
return options{
- EnabledServices: []service{blobService, queueService, tableService},
+ EnabledServices: []Service{BlobService, QueueService, TableService},
+ }
+}
+
+// Satisfy the testcontainers.ContainerCustomizer interface
+var _ testcontainers.ContainerCustomizer = (Option)(nil)
+
+// Option is an option for the Azurite container.
+type Option func(*options) error
+
+// Customize is a NOOP. It's defined to satisfy the testcontainers.ContainerCustomizer interface.
+func (o Option) Customize(*testcontainers.GenericContainerRequest) error {
+ // NOOP to satisfy interface.
+ return nil
+}
+
+// WithEnabledServices is a custom option to specify which services should be enabled.
+func WithEnabledServices(services ...Service) Option {
+ return func(o *options) error {
+ if len(services) == 0 {
+ services = []Service{BlobService, QueueService, TableService}
+ } else {
+ seen := make(map[Service]bool, len(services))
+ for _, srv := range services {
+ if seen[srv] {
+ return fmt.Errorf("duplicate service: %s", srv)
+ }
+ seen[srv] = true
+
+ switch srv {
+ case BlobService, QueueService, TableService:
+ // valid service, continue
+ default:
+ return fmt.Errorf("unknown service: %s", srv)
+ }
+ }
+ }
+
+ o.EnabledServices = services
+ return nil
}
}
diff --git a/modules/azure/azurite/services.go b/modules/azure/azurite/services.go
index 3b1fb5a23d..69c9ade850 100644
--- a/modules/azure/azurite/services.go
+++ b/modules/azure/azurite/services.go
@@ -1,31 +1,15 @@
package azurite
const (
- // blobService is the service name for the Blob service
- blobService Service = "blob"
-
- // Deprecated: this constant is kept for backward compatibility, but it'll be removed in the next major version.
// BlobService is the service name for the Blob service
- BlobService Service = blobService
-
- // queueService is the service name for the Queue service
- queueService Service = "queue"
+ BlobService Service = "blob"
- // Deprecated: this constant is kept for backward compatibility, but it'll be removed in the next major version.
// QueueService is the service name for the Queue service
- QueueService Service = queueService
+ QueueService Service = "queue"
- // tableService is the service name for the Table service
- tableService Service = "table"
-
- // Deprecated: this constant is kept for backward compatibility, but it'll be removed in the next major version.
// TableService is the service name for the Table service
- TableService Service = tableService
+ TableService Service = "table"
)
-// Deprecated: this type is kept for backward compatibility, but it'll be removed in the next major version.
// Service is the type for the services that Azurite can provide
-type Service = service
-
-// service is the type for the services that Azurite can provide
-type service string
+type Service string
diff --git a/modules/azure/eventhubs/options.go b/modules/azure/eventhubs/options.go
index 25f19ee0a4..e749996b6d 100644
--- a/modules/azure/eventhubs/options.go
+++ b/modules/azure/eventhubs/options.go
@@ -23,7 +23,7 @@ func defaultOptions() options {
}
}
-// Satisfy the testcontainers.CustomizeRequestOption interface
+// Satisfy the testcontainers.ContainerCustomizer interface
var _ testcontainers.ContainerCustomizer = (Option)(nil)
// Option is an option for the EventHubs container.
diff --git a/modules/azure/servicebus/options.go b/modules/azure/servicebus/options.go
index 24de1041fe..f9396515b6 100644
--- a/modules/azure/servicebus/options.go
+++ b/modules/azure/servicebus/options.go
@@ -23,7 +23,7 @@ func defaultOptions() options {
}
}
-// Satisfy the testcontainers.CustomizeRequestOption interface
+// Satisfy the testcontainers.ContainerCustomizer interface
var _ testcontainers.ContainerCustomizer = (Option)(nil)
// Option is an option for the ServiceBus container.