From 72e4633300fbbe619e88bfcbc9d974666c702ad7 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 14 Oct 2025 16:57:54 +1100 Subject: [PATCH 01/10] feat(azurite): reduce time/memory by running specific sub-services --- modules/azure/azurite/azurite.go | 39 ++++++++++++++++++-------- modules/azure/azurite/azurite_test.go | 27 ++++++++++++++++++ modules/azure/azurite/examples_test.go | 3 ++ modules/azure/azurite/options.go | 28 ++++++++++++++++++ 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/modules/azure/azurite/azurite.go b/modules/azure/azurite/azurite.go index 9eeabd5a54..ea85d560e5 100644 --- a/modules/azure/azurite/azurite.go +++ b/modules/azure/azurite/azurite.go @@ -72,35 +72,50 @@ func (c *Container) serviceURL(ctx context.Context, srv service) (string, error) // 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") + cmd = append(cmd, "--blobHost", "0.0.0.0", "--blobPort", BlobPort) + exposedPorts = append(exposedPorts, BlobPort) waitingFor = append(waitingFor, wait.ForListeningPort(BlobPort)) case QueueService: - moduleCmd = append(moduleCmd, "--queueHost", "0.0.0.0") + cmd = append(cmd, "--queueHost", "0.0.0.0", "--queuePort", QueuePort) + exposedPorts = append(exposedPorts, QueuePort) waitingFor = append(waitingFor, wait.ForListeningPort(QueuePort)) case TableService: - moduleCmd = append(moduleCmd, "--tableHost", "0.0.0.0") + cmd = append(cmd, "--tableHost", "0.0.0.0", "--tablePort", TablePort) + exposedPorts = append(exposedPorts, TablePort) waitingFor = append(waitingFor, wait.ForListeningPort(TablePort)) } } - 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..e947a0aeec 100644 --- a/modules/azure/azurite/azurite_test.go +++ b/modules/azure/azurite/azurite_test.go @@ -36,6 +36,33 @@ func TestAzurite_inMemoryPersistence(t *testing.T) { }) } +func TestAzurite_enabledServices(t *testing.T) { + ctx := context.Background() + + invalidService := azurite.Service("invalid") + services := []azurite.Service{azurite.BlobService, azurite.QueueService, azurite.TableService, invalidService} + 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.WithInMemoryPersistence(0), azurite.WithEnabledServices(service)) + testcontainers.CleanupContainer(t, ctr) + if service == invalidService { + require.Error(t, err) + return + } + require.NoError(t, err) + + for _, s := range services { + _, err = ctr.ServiceURL(ctx, s) + if s == service { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } + }) + } +} + 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..360350794f 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -17,6 +17,34 @@ func defaultOptions() options { } } +// Satisfy the testcontainers.CustomizeRequestOption 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 { + for _, s := range services { + switch s { + case blobService, queueService, tableService: + default: + return fmt.Errorf("unknown service: %s", s) + } + } + + o.EnabledServices = services + return nil + } +} + // WithInMemoryPersistence is a custom option to enable in-memory persistence for Azurite. // This option is only available for Azurite v3.28.0 and later. func WithInMemoryPersistence(megabytes float64) testcontainers.CustomizeRequestOption { From bda73a33de2af8287508ae94b22e23f37ff5ff91 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 14 Oct 2025 17:23:25 +1100 Subject: [PATCH 02/10] feat(azurite): restore defaults if specify no services --- modules/azure/azurite/options.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go index 360350794f..fe5b62a2a3 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -32,11 +32,15 @@ func (o Option) Customize(*testcontainers.GenericContainerRequest) error { // WithEnabledServices is a custom option to specify which services should be enabled. func WithEnabledServices(services ...service) Option { return func(o *options) error { - for _, s := range services { - switch s { - case blobService, queueService, tableService: - default: - return fmt.Errorf("unknown service: %s", s) + if len(services) == 0 { + services = []service{blobService, queueService, tableService} + } else { + for _, s := range services { + switch s { + case blobService, queueService, tableService: + default: + return fmt.Errorf("unknown service: %s", s) + } } } From 5b64ae527c6c244c1e2223753ba453ce29bc0aba Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 14 Oct 2025 17:30:13 +1100 Subject: [PATCH 03/10] fix(azurite): minor code documentation correction --- modules/azure/azurite/options.go | 3 ++- modules/azure/eventhubs/options.go | 2 +- modules/azure/servicebus/options.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go index fe5b62a2a3..f366b21f19 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -17,7 +17,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 Azurite container. @@ -38,6 +38,7 @@ func WithEnabledServices(services ...service) Option { for _, s := range services { switch s { case blobService, queueService, tableService: + // valid service, continue default: return fmt.Errorf("unknown service: %s", s) } 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. From 2e20ed6943db5ce220338749da86af44aa9f4da7 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 14 Oct 2025 19:02:39 +1100 Subject: [PATCH 04/10] feat(azurite): protect against dupe services --- modules/azure/azurite/options.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go index f366b21f19..9ef5c7a4c8 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -35,7 +35,13 @@ func WithEnabledServices(services ...service) Option { if len(services) == 0 { services = []service{blobService, queueService, tableService} } else { + seen := make(map[service]bool, len(services)) for _, s := range services { + if seen[s] { + return fmt.Errorf("duplicate service: %s", s) + } + seen[s] = true + switch s { case blobService, queueService, tableService: // valid service, continue From 57dc66392405edc86d18df96638c632ac58fd8b2 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Wed, 15 Oct 2025 14:10:05 +1100 Subject: [PATCH 05/10] feat(azurite): restore previously deprecated service APIs --- modules/azure/azurite/azurite.go | 17 ++++++++--------- modules/azure/azurite/options.go | 12 ++++++------ modules/azure/azurite/services.go | 24 ++++-------------------- 3 files changed, 18 insertions(+), 35 deletions(-) diff --git a/modules/azure/azurite/azurite.go b/modules/azure/azurite/azurite.go index ea85d560e5..f0ae0d1a4d 100644 --- a/modules/azure/azurite/azurite.go +++ b/modules/azure/azurite/azurite.go @@ -33,7 +33,6 @@ 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) @@ -41,27 +40,27 @@ func (c *Container) ServiceURL(ctx context.Context, srv Service) (string, error) // 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) { +func (c *Container) serviceURL(ctx context.Context, srv Service) (string, error) { var port nat.Port switch srv { - case blobService: + case BlobService: port = BlobPort - case queueService: + case QueueService: port = QueuePort - case tableService: + case TableService: port = TablePort default: return "", fmt.Errorf("unknown service: %s", srv) @@ -83,7 +82,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom } entrypoint := "azurite" - if len(settings.EnabledServices) == 1 && settings.EnabledServices[0] != tableService { + 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]) } diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go index 9ef5c7a4c8..6efc278264 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -8,12 +8,12 @@ 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}, } } @@ -30,12 +30,12 @@ func (o Option) Customize(*testcontainers.GenericContainerRequest) error { } // WithEnabledServices is a custom option to specify which services should be enabled. -func WithEnabledServices(services ...service) Option { +func WithEnabledServices(services ...Service) Option { return func(o *options) error { if len(services) == 0 { - services = []service{blobService, queueService, tableService} + services = []Service{BlobService, QueueService, TableService} } else { - seen := make(map[service]bool, len(services)) + seen := make(map[Service]bool, len(services)) for _, s := range services { if seen[s] { return fmt.Errorf("duplicate service: %s", s) @@ -43,7 +43,7 @@ func WithEnabledServices(services ...service) Option { seen[s] = true switch s { - case blobService, queueService, tableService: + case BlobService, QueueService, TableService: // valid service, continue default: return fmt.Errorf("unknown service: %s", s) 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 From 7dda54b2e7e9b9b0ed9745969c63212224853dfc Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Wed, 15 Oct 2025 14:11:52 +1100 Subject: [PATCH 06/10] chore(azurite): minor refactoring and cleanup --- modules/azure/azurite/azurite.go | 39 +++++++++++++-------------- modules/azure/azurite/azurite_test.go | 11 ++++---- modules/azure/azurite/options.go | 12 ++++----- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/modules/azure/azurite/azurite.go b/modules/azure/azurite/azurite.go index f0ae0d1a4d..5122ecdce0 100644 --- a/modules/azure/azurite/azurite.go +++ b/modules/azure/azurite/azurite.go @@ -35,7 +35,12 @@ type Container struct { // 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 @@ -53,20 +58,17 @@ func (c *Container) TableServiceURL(ctx context.Context) (string, error) { 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 + return BlobPort, nil case QueueService: - port = QueuePort + return QueuePort, nil case TableService: - port = TablePort + 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 @@ -93,21 +95,16 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom 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: - cmd = append(cmd, "--blobHost", "0.0.0.0", "--blobPort", BlobPort) - exposedPorts = append(exposedPorts, BlobPort) - waitingFor = append(waitingFor, wait.ForListeningPort(BlobPort)) - case QueueService: - cmd = append(cmd, "--queueHost", "0.0.0.0", "--queuePort", QueuePort) - exposedPorts = append(exposedPorts, QueuePort) - waitingFor = append(waitingFor, wait.ForListeningPort(QueuePort)) - case TableService: - cmd = append(cmd, "--tableHost", "0.0.0.0", "--tablePort", TablePort) - exposedPorts = append(exposedPorts, TablePort) - 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), string(port)) + exposedPorts = append(exposedPorts, string(port)) + waitingFor = append(waitingFor, wait.ForListeningPort(port)) } moduleOpts = append(moduleOpts, diff --git a/modules/azure/azurite/azurite_test.go b/modules/azure/azurite/azurite_test.go index e947a0aeec..b03d3bd40f 100644 --- a/modules/azure/azurite/azurite_test.go +++ b/modules/azure/azurite/azurite_test.go @@ -39,21 +39,20 @@ func TestAzurite_inMemoryPersistence(t *testing.T) { func TestAzurite_enabledServices(t *testing.T) { ctx := context.Background() - invalidService := azurite.Service("invalid") - services := []azurite.Service{azurite.BlobService, azurite.QueueService, azurite.TableService, invalidService} + services := []azurite.Service{azurite.BlobService, azurite.QueueService, azurite.TableService, "invalid"} 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.WithInMemoryPersistence(0), azurite.WithEnabledServices(service)) testcontainers.CleanupContainer(t, ctr) - if service == invalidService { + if service == "invalid" { require.Error(t, err) return } require.NoError(t, err) - for _, s := range services { - _, err = ctr.ServiceURL(ctx, s) - if s == service { + for _, srv := range services { + _, err = ctr.ServiceURL(ctx, srv) + if srv == service { require.NoError(t, err) } else { require.Error(t, err) diff --git a/modules/azure/azurite/options.go b/modules/azure/azurite/options.go index 6efc278264..1666894c7c 100644 --- a/modules/azure/azurite/options.go +++ b/modules/azure/azurite/options.go @@ -36,17 +36,17 @@ func WithEnabledServices(services ...Service) Option { services = []Service{BlobService, QueueService, TableService} } else { seen := make(map[Service]bool, len(services)) - for _, s := range services { - if seen[s] { - return fmt.Errorf("duplicate service: %s", s) + for _, srv := range services { + if seen[srv] { + return fmt.Errorf("duplicate service: %s", srv) } - seen[s] = true + seen[srv] = true - switch s { + switch srv { case BlobService, QueueService, TableService: // valid service, continue default: - return fmt.Errorf("unknown service: %s", s) + return fmt.Errorf("unknown service: %s", srv) } } } From f51a656315957d0c2b67669a24fa729b7c72707a Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Thu, 16 Oct 2025 07:46:53 +1100 Subject: [PATCH 07/10] fix(azurite): pass port without proto to cmd args --- modules/azure/azurite/azurite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/azurite/azurite.go b/modules/azure/azurite/azurite.go index 5122ecdce0..83a4530310 100644 --- a/modules/azure/azurite/azurite.go +++ b/modules/azure/azurite/azurite.go @@ -102,7 +102,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } - cmd = append(cmd, fmt.Sprintf("--%sHost", srv), "0.0.0.0", fmt.Sprintf("--%sPort", srv), string(port)) + 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)) } From c67652c593ac6dd4cff5936cd42c07c8e2b3134e Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Mon, 20 Oct 2025 07:59:19 +1100 Subject: [PATCH 08/10] docs(azurite): document WithEnabledServices --- docs/modules/azure.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/modules/azure.md b/docs/modules/azure.md index 8260970369..f79b5991e7 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 + +- Since :material-tag: v0.40.0 + +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 From 5d0edaeb262d2c89f9f6f16655e4875a854f1b7b Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 21 Oct 2025 20:42:21 +1100 Subject: [PATCH 09/10] docs(azurite): tweak next release wording --- docs/modules/azure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/azure.md b/docs/modules/azure.md index f79b5991e7..695e0efeb8 100644 --- a/docs/modules/azure.md +++ b/docs/modules/azure.md @@ -63,7 +63,7 @@ When starting the Azurite container, you can pass options in a variadic way to c #### WithEnabledServices -- Since :material-tag: v0.40.0 +- 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)`. From 2d6e5fb86bbb9452c7af4f369210620861c42d34 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 21 Oct 2025 20:47:48 +1100 Subject: [PATCH 10/10] chore(azurite): unit test for duplicate services --- modules/azure/azurite/azurite_test.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/azure/azurite/azurite_test.go b/modules/azure/azurite/azurite_test.go index b03d3bd40f..37e693bd34 100644 --- a/modules/azure/azurite/azurite_test.go +++ b/modules/azure/azurite/azurite_test.go @@ -39,15 +39,11 @@ func TestAzurite_inMemoryPersistence(t *testing.T) { func TestAzurite_enabledServices(t *testing.T) { ctx := context.Background() - services := []azurite.Service{azurite.BlobService, azurite.QueueService, azurite.TableService, "invalid"} + 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.WithInMemoryPersistence(0), azurite.WithEnabledServices(service)) + ctr, err := azurite.Run(ctx, "mcr.microsoft.com/azure-storage/azurite:3.33.0", azurite.WithEnabledServices(service)) testcontainers.CleanupContainer(t, ctr) - if service == "invalid" { - require.Error(t, err) - return - } require.NoError(t, err) for _, srv := range services { @@ -60,6 +56,16 @@ func TestAzurite_enabledServices(t *testing.T) { } }) } + + 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) {