From c8253f764ba8dba8b6dd3085efceb1b71fe2f16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:13:12 +0200 Subject: [PATCH 01/11] chore(gcloud): use Run in deprecated constructors --- modules/gcloud/bigquery.go | 24 +++++++++++------------- modules/gcloud/bigtable.go | 25 +++++++++++++------------ modules/gcloud/datastore.go | 22 ++++++++++------------ modules/gcloud/firestore.go | 25 +++++++++++++------------ modules/gcloud/gcloud.go | 13 +++++-------- modules/gcloud/pubsub.go | 25 +++++++++++++------------ modules/gcloud/spanner.go | 19 ++++++++++--------- 7 files changed, 75 insertions(+), 78 deletions(-) diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index 5eabedddab..7e7cae63d1 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -18,34 +18,32 @@ func RunBigQueryContainer(ctx context.Context, opts ...testcontainers.ContainerC // RunBigQuery creates an instance of the GCloud container type for BigQuery. // The URI uses http:// as the protocol. func RunBigQuery(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9050/tcp", "9060/tcp"}, - WaitingFor: wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStartupTimeout(time.Second * 5), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("9050/tcp", "9060/tcp"), + testcontainers.WithWaitStrategy(wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStartupTimeout(time.Second * 5)), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - req.Cmd = append(req.Cmd, "--project", settings.ProjectID) + moduleOpts = append(moduleOpts, testcontainers.WithCmdArgs("--project", settings.ProjectID)) // Process data yaml file only for the BigQuery container. if settings.bigQueryDataYaml != nil { containerPath := "/testcontainers-data.yaml" - req.Cmd = append(req.Cmd, "--data-from-yaml", containerPath) + moduleOpts = append(moduleOpts, testcontainers.WithCmdArgs("--data-from-yaml", containerPath)) - req.Files = append(req.Files, testcontainers.ContainerFile{ + moduleOpts = append(moduleOpts, testcontainers.WithFiles(testcontainers.ContainerFile{ Reader: settings.bigQueryDataYaml, ContainerFilePath: containerPath, FileMode: 0o644, - }) + })) } - return newGCloudContainer(ctx, req, 9050, settings, "http") + return newGCloudContainer(ctx, img, 9050, settings, "http", moduleOpts...) } diff --git a/modules/gcloud/bigtable.go b/modules/gcloud/bigtable.go index e133b55e46..153d7f9fa3 100644 --- a/modules/gcloud/bigtable.go +++ b/modules/gcloud/bigtable.go @@ -16,25 +16,26 @@ func RunBigTableContainer(ctx context.Context, opts ...testcontainers.ContainerC // Deprecated: use [bigtable.Run] instead // RunBigTable creates an instance of the GCloud container type for BigTable. func RunBigTable(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9000/tcp"}, - WaitingFor: wait.ForLog("running"), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("9000/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("9000/tcp"), + wait.ForLog("running")), + ), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000 --project=" + settings.ProjectID, - } + "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000 --project="+settings.ProjectID, + )) - return newGCloudContainer(ctx, req, 9000, settings, "") + return newGCloudContainer(ctx, img, 9000, settings, "", moduleOpts...) } diff --git a/modules/gcloud/datastore.go b/modules/gcloud/datastore.go index 02fbd73f6a..a435f60eab 100644 --- a/modules/gcloud/datastore.go +++ b/modules/gcloud/datastore.go @@ -16,25 +16,23 @@ func RunDatastoreContainer(ctx context.Context, opts ...testcontainers.Container // Deprecated: use [datastore.Run] instead // RunDatastore creates an instance of the GCloud container type for Datastore. func RunDatastore(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8081/tcp"}, - WaitingFor: wait.ForHTTP("/").WithPort("8081/tcp"), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("8081/tcp"), + testcontainers.WithWaitStrategy(wait.ForHTTP("/").WithPort("8081/tcp")), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators datastore start --host-port 0.0.0.0:8081 --project=" + settings.ProjectID, - } + "gcloud beta emulators datastore start --host-port 0.0.0.0:8081 --project="+settings.ProjectID, + )) - return newGCloudContainer(ctx, req, 8081, settings, "") + return newGCloudContainer(ctx, img, 8081, settings, "", moduleOpts...) } diff --git a/modules/gcloud/firestore.go b/modules/gcloud/firestore.go index b333a64f44..5a459e3fd8 100644 --- a/modules/gcloud/firestore.go +++ b/modules/gcloud/firestore.go @@ -16,25 +16,26 @@ func RunFirestoreContainer(ctx context.Context, opts ...testcontainers.Container // Deprecated: use [firestore.Run] instead // RunFirestore creates an instance of the GCloud container type for Firestore. func RunFirestore(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8080/tcp"}, - WaitingFor: wait.ForLog("running"), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("8080/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("8080/tcp"), + wait.ForLog("running"), + )), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators firestore start --host-port 0.0.0.0:8080 --project=" + settings.ProjectID, - } + "gcloud beta emulators firestore start --host-port 0.0.0.0:8080 --project="+settings.ProjectID, + )) - return newGCloudContainer(ctx, req, 8080, settings, "") + return newGCloudContainer(ctx, img, 8080, settings, "", moduleOpts...) } diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index c814b99e7b..ce1f3fc1a3 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -27,14 +27,14 @@ type GCloudContainer struct { } // newGCloudContainer creates a new GCloud container, obtaining the URL to access the container from the specified port. -func newGCloudContainer(ctx context.Context, req testcontainers.GenericContainerRequest, port int, settings options, proto string) (*GCloudContainer, error) { - container, err := testcontainers.GenericContainer(ctx, req) +func newGCloudContainer(ctx context.Context, img string, port int, settings options, proto string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { + container, err := testcontainers.Run(ctx, img, opts...) var c *GCloudContainer if container != nil { c = &GCloudContainer{Container: container, Settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run gcloud container: %w", err) } endpoint, err := c.PortEndpoint(ctx, nat.Port(fmt.Sprintf("%d/tcp", port)), proto) @@ -97,17 +97,14 @@ func WithDataYAML(r io.Reader) Option { } // applyOptions applies the options to the container request and returns the settings. -func applyOptions(req *testcontainers.GenericContainerRequest, opts []testcontainers.ContainerCustomizer) (options, error) { +func applyOptions(opts []testcontainers.ContainerCustomizer) (options, error) { settings := defaultOptions() for _, opt := range opts { if apply, ok := opt.(Option); ok { if err := apply(&settings); err != nil { - return options{}, err + return options{}, fmt.Errorf("apply option: %w", err) } } - if err := opt.Customize(req); err != nil { - return options{}, err - } } return settings, nil diff --git a/modules/gcloud/pubsub.go b/modules/gcloud/pubsub.go index 2d637563dc..a7d2ed78ae 100644 --- a/modules/gcloud/pubsub.go +++ b/modules/gcloud/pubsub.go @@ -16,25 +16,26 @@ func RunPubsubContainer(ctx context.Context, opts ...testcontainers.ContainerCus // Deprecated: use [pubsub.Run] instead // RunPubsub creates an instance of the GCloud container type for Pubsub. func RunPubsub(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8085/tcp"}, - WaitingFor: wait.ForLog("started"), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("8085/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("8085/tcp"), + wait.ForLog("started"), + )), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085 --project=" + settings.ProjectID, - } + "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085 --project="+settings.ProjectID, + )) - return newGCloudContainer(ctx, req, 8085, settings, "") + return newGCloudContainer(ctx, img, 8085, settings, "", moduleOpts...) } diff --git a/modules/gcloud/spanner.go b/modules/gcloud/spanner.go index b5e9bb57f3..9bc139fb1a 100644 --- a/modules/gcloud/spanner.go +++ b/modules/gcloud/spanner.go @@ -16,19 +16,20 @@ func RunSpannerContainer(ctx context.Context, opts ...testcontainers.ContainerCu // Deprecated: use [spanner.Run] instead // RunSpanner creates an instance of the GCloud container type for Spanner. func RunSpanner(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9010/tcp"}, - WaitingFor: wait.ForLog("Cloud Spanner emulator running"), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("9010/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("9010/tcp"), + wait.ForLog("Cloud Spanner emulator running"), + )), } - settings, err := applyOptions(&req, opts) + moduleOpts = append(moduleOpts, opts...) + + settings, err := applyOptions(opts) if err != nil { return nil, err } - return newGCloudContainer(ctx, req, 9010, settings, "") + return newGCloudContainer(ctx, img, 9010, settings, "", moduleOpts...) } From 7e95a2ec0102435d218cdb06c7584a01be686b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:21:58 +0200 Subject: [PATCH 02/11] chore(bigquery): use Run function --- modules/gcloud/bigquery/bigquery.go | 37 ++++++++++-------------- modules/gcloud/bigquery/bigquery_test.go | 9 ++---- modules/gcloud/bigquery/options.go | 10 +++---- 3 files changed, 24 insertions(+), 32 deletions(-) diff --git a/modules/gcloud/bigquery/bigquery.go b/modules/gcloud/bigquery/bigquery.go index 899d16e86e..ea792de351 100644 --- a/modules/gcloud/bigquery/bigquery.go +++ b/modules/gcloud/bigquery/bigquery.go @@ -36,41 +36,36 @@ func (c *Container) URI() string { // Run creates an instance of the BigQuery GCloud container type. // The URI uses http:// as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9050/tcp", "9060/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("9050/tcp"), - wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStatusCodeMatcher(func(status int) bool { - return status == 200 - }).WithStartupTimeout(time.Second*5), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("9050/tcp", "9060/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("9050/tcp"), + wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStatusCodeMatcher(func(status int) bool { + return status == 200 + }).WithStartupTimeout(time.Second*5), + )), } settings := defaultOptions() for _, opt := range opts { if apply, ok := opt.(Option); ok { if err := apply(&settings); err != nil { - return nil, err + return nil, fmt.Errorf("apply option: %w", err) } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } - req.Cmd = append(req.Cmd, "--project", settings.ProjectID) + moduleOpts = append(moduleOpts, opts...) + + moduleOpts = append(moduleOpts, testcontainers.WithCmdArgs("--project", settings.ProjectID)) - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run bigquery: %w", err) } portEndpoint, err := c.PortEndpoint(ctx, "9050/tcp", "http") diff --git a/modules/gcloud/bigquery/bigquery_test.go b/modules/gcloud/bigquery/bigquery_test.go index 3a4dc346a3..96bf03883c 100644 --- a/modules/gcloud/bigquery/bigquery_test.go +++ b/modules/gcloud/bigquery/bigquery_test.go @@ -76,15 +76,12 @@ func TestBigQueryWithDataYAML(t *testing.T) { tcbigquery.WithDataYAML(bytes.NewReader(dataYaml)), ) testcontainers.CleanupContainer(t, bigQueryContainer) - require.EqualError(t, err, `data yaml already exists`) + require.ErrorContains(t, err, `data yaml already exists`) }) t.Run("multi-value-not-set", func(t *testing.T) { - noValueOption := func() testcontainers.CustomizeRequestOption { - return func(req *testcontainers.GenericContainerRequest) error { - req.Cmd = append(req.Cmd, "--data-from-yaml") - return nil - } + noValueOption := func() testcontainers.ContainerCustomizer { + return testcontainers.WithCmdArgs("--data-from-yaml") } bigQueryContainer, err := tcbigquery.Run( diff --git a/modules/gcloud/bigquery/options.go b/modules/gcloud/bigquery/options.go index 16e080bcee..56b50f81b0 100644 --- a/modules/gcloud/bigquery/options.go +++ b/modules/gcloud/bigquery/options.go @@ -34,14 +34,14 @@ func WithDataYAML(r io.Reader) testcontainers.CustomizeRequestOption { return errors.New("data yaml already exists") } - req.Cmd = append(req.Cmd, "--data-from-yaml", bigQueryDataYamlPath) + if err := testcontainers.WithCmdArgs("--data-from-yaml", bigQueryDataYamlPath)(req); err != nil { + return err + } - req.Files = append(req.Files, testcontainers.ContainerFile{ + return testcontainers.WithFiles(testcontainers.ContainerFile{ Reader: r, ContainerFilePath: bigQueryDataYamlPath, FileMode: 0o644, - }) - - return nil + })(req) } } From 4dd6e185c944e5e18a43aef00ab5a9dbe560fe33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:27:56 +0200 Subject: [PATCH 03/11] chore(bigtable): use Run function --- modules/gcloud/bigtable/bigtable.go | 35 +++++++++++++---------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/modules/gcloud/bigtable/bigtable.go b/modules/gcloud/bigtable/bigtable.go index 5d6a7c98b5..7ff2fe33cb 100644 --- a/modules/gcloud/bigtable/bigtable.go +++ b/modules/gcloud/bigtable/bigtable.go @@ -32,16 +32,12 @@ func (c *Container) URI() string { // Run creates an instance of the BigTable GCloud container type. // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9000/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("9000/tcp"), - wait.ForLog("running"), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("9000/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("9000/tcp"), + wait.ForLog("running"), + )), } settings := defaultOptions() @@ -51,24 +47,23 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000 --project=" + settings.ProjectID, - } + "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000 --project="+settings.ProjectID, + )) + + moduleOpts = append(moduleOpts, opts...) - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run bigtable: %w", err) } portEndpoint, err := c.PortEndpoint(ctx, "9000/tcp", "") From 4e0b01b5b410b0f353322b122504a92657d136ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:31:09 +0200 Subject: [PATCH 04/11] chore(datastore): use Run function --- modules/gcloud/datastore/datastore.go | 35 ++++++++++++--------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/modules/gcloud/datastore/datastore.go b/modules/gcloud/datastore/datastore.go index b421925079..b920f954ac 100644 --- a/modules/gcloud/datastore/datastore.go +++ b/modules/gcloud/datastore/datastore.go @@ -32,16 +32,12 @@ func (c *Container) URI() string { // Run creates an instance of the Datastore GCloud container type. // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8081/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("8081/tcp"), - wait.ForHTTP("/").WithPort("8081/tcp"), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts("8081/tcp"), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort("8081/tcp"), + wait.ForHTTP("/").WithPort("8081/tcp"), + )), } settings := defaultOptions() @@ -51,24 +47,23 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators datastore start --host-port 0.0.0.0:8081 --project=" + settings.ProjectID, - } + "gcloud beta emulators datastore start --host-port 0.0.0.0:8081 --project="+settings.ProjectID, + )) + + moduleOpts = append(moduleOpts, opts...) - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run datastore: %w", err) } portEndpoint, err := c.PortEndpoint(ctx, "8081/tcp", "") From a530e886a76a61e424c11681b54c4646d1aacd38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:33:37 +0200 Subject: [PATCH 05/11] chore: extract ports to constants --- modules/gcloud/bigquery/bigquery.go | 13 +++++++++---- modules/gcloud/bigtable/bigtable.go | 12 +++++++----- modules/gcloud/datastore/datastore.go | 14 ++++++++------ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/gcloud/bigquery/bigquery.go b/modules/gcloud/bigquery/bigquery.go index ea792de351..2f9291ec8d 100644 --- a/modules/gcloud/bigquery/bigquery.go +++ b/modules/gcloud/bigquery/bigquery.go @@ -15,6 +15,11 @@ const ( // bigQueryDataYamlPath is the path to the data yaml file in the container. bigQueryDataYamlPath = "/testcontainers-data.yaml" + + defaultPortNumber9050 = "9050" + defaultPortNumber9060 = "9060" + defaultPort9050 = defaultPortNumber9050 + "/tcp" + defaultPort9060 = defaultPortNumber9060 + "/tcp" ) // Container represents the BigQuery container type used in the module @@ -37,10 +42,10 @@ func (c *Container) URI() string { // The URI uses http:// as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { moduleOpts := []testcontainers.ContainerCustomizer{ - testcontainers.WithExposedPorts("9050/tcp", "9060/tcp"), + testcontainers.WithExposedPorts(defaultPort9050, defaultPort9060), testcontainers.WithWaitStrategy(wait.ForAll( - wait.ForListeningPort("9050/tcp"), - wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStatusCodeMatcher(func(status int) bool { + wait.ForListeningPort(defaultPort9050), + wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort(defaultPort9050).WithStatusCodeMatcher(func(status int) bool { return status == 200 }).WithStartupTimeout(time.Second*5), )), @@ -68,7 +73,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return c, fmt.Errorf("run bigquery: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "9050/tcp", "http") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort9050, "http") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } diff --git a/modules/gcloud/bigtable/bigtable.go b/modules/gcloud/bigtable/bigtable.go index 7ff2fe33cb..302506ae4a 100644 --- a/modules/gcloud/bigtable/bigtable.go +++ b/modules/gcloud/bigtable/bigtable.go @@ -10,7 +10,9 @@ import ( const ( // DefaultProjectID is the default project ID for the BigTable container. - DefaultProjectID = "test-project" + DefaultProjectID = "test-project" + defaultPortNumber = "9000" + defaultPort = defaultPortNumber + "/tcp" ) // Container represents the BigTable container type used in the module @@ -33,9 +35,9 @@ func (c *Container) URI() string { // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { moduleOpts := []testcontainers.ContainerCustomizer{ - testcontainers.WithExposedPorts("9000/tcp"), + testcontainers.WithExposedPorts(defaultPort), testcontainers.WithWaitStrategy(wait.ForAll( - wait.ForListeningPort("9000/tcp"), + wait.ForListeningPort(defaultPort), wait.ForLog("running"), )), } @@ -52,7 +54,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators bigtable start --host-port 0.0.0.0:9000 --project="+settings.ProjectID, + "gcloud beta emulators bigtable start --host-port 0.0.0.0:"+defaultPortNumber+" --project="+settings.ProjectID, )) moduleOpts = append(moduleOpts, opts...) @@ -66,7 +68,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return c, fmt.Errorf("run bigtable: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "9000/tcp", "") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort, "") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } diff --git a/modules/gcloud/datastore/datastore.go b/modules/gcloud/datastore/datastore.go index b920f954ac..0b30b7c2a6 100644 --- a/modules/gcloud/datastore/datastore.go +++ b/modules/gcloud/datastore/datastore.go @@ -10,7 +10,9 @@ import ( const ( // DefaultProjectID is the default project ID for the Datastore container. - DefaultProjectID = "test-project" + DefaultProjectID = "test-project" + defaultPortNumber = "8081" + defaultPort = defaultPortNumber + "/tcp" ) // Container represents the Datastore container type used in the module @@ -33,10 +35,10 @@ func (c *Container) URI() string { // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { moduleOpts := []testcontainers.ContainerCustomizer{ - testcontainers.WithExposedPorts("8081/tcp"), + testcontainers.WithExposedPorts(defaultPort), testcontainers.WithWaitStrategy(wait.ForAll( - wait.ForListeningPort("8081/tcp"), - wait.ForHTTP("/").WithPort("8081/tcp"), + wait.ForListeningPort(defaultPort), + wait.ForHTTP("/").WithPort(defaultPort), )), } @@ -52,7 +54,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators datastore start --host-port 0.0.0.0:8081 --project="+settings.ProjectID, + "gcloud beta emulators datastore start --host-port 0.0.0.0:"+defaultPortNumber+" --project="+settings.ProjectID, )) moduleOpts = append(moduleOpts, opts...) @@ -66,7 +68,7 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return c, fmt.Errorf("run datastore: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "8081/tcp", "") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort, "") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } From 9e42d5c523a9dc32d5524e35919c5db4ef038394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:36:08 +0200 Subject: [PATCH 06/11] chore(firestore): use Run function --- modules/gcloud/firestore/firestore.go | 41 +++++++++++++-------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/modules/gcloud/firestore/firestore.go b/modules/gcloud/firestore/firestore.go index 1f7f417626..5b7b1a7742 100644 --- a/modules/gcloud/firestore/firestore.go +++ b/modules/gcloud/firestore/firestore.go @@ -10,7 +10,9 @@ import ( const ( // DefaultProjectID is the default project ID for the Firestore container. - DefaultProjectID = "test-project" + DefaultProjectID = "test-project" + defaultPortNumber = "8080" + defaultPort = defaultPortNumber + "/tcp" ) // Container represents the Firestore container type used in the module @@ -32,16 +34,12 @@ func (c *Container) URI() string { // Run creates an instance of the Firestore GCloud container type. // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8080/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("8080/tcp"), - wait.ForLog("running"), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts(defaultPort), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort(defaultPort), + wait.ForLog("running"), + )), } settings := defaultOptions() @@ -51,9 +49,6 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } gcloudParameters := "--project=" + settings.ProjectID @@ -61,22 +56,24 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom gcloudParameters += " --database-mode=datastore-mode" } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators firestore start --host-port 0.0.0.0:8080 " + gcloudParameters, - } + "gcloud beta emulators firestore start --host-port 0.0.0.0:"+defaultPortNumber+" "+gcloudParameters, + )) + + moduleOpts = append(moduleOpts, opts...) - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run firestore: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "8080/tcp", "") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort, "") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } From 463e550139c9c1ad6cdacf9ba9fdcf1035753e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:37:11 +0200 Subject: [PATCH 07/11] chore(pubsub): use Run function --- modules/gcloud/pubsub/pubsub.go | 39 ++++++++++++++------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/modules/gcloud/pubsub/pubsub.go b/modules/gcloud/pubsub/pubsub.go index d41e55d21a..8712ddb4dc 100644 --- a/modules/gcloud/pubsub/pubsub.go +++ b/modules/gcloud/pubsub/pubsub.go @@ -10,7 +10,9 @@ import ( const ( // DefaultProjectID is the default project ID for the Pubsub container. - DefaultProjectID = "test-project" + DefaultProjectID = "test-project" + defaultPortNumber = "8085" + defaultPort = defaultPortNumber + "/tcp" ) // Container represents the Pubsub container type used in the module @@ -32,16 +34,12 @@ func (c *Container) URI() string { // Run creates an instance of the Pubsub GCloud container type. // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"8085/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("8085/tcp"), - wait.ForLog("started"), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts(defaultPort), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort(defaultPort), + wait.ForLog("started"), + )), } settings := defaultOptions() @@ -51,27 +49,24 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } - req.Cmd = []string{ + moduleOpts = append(moduleOpts, testcontainers.WithCmd( "/bin/sh", "-c", - "gcloud beta emulators pubsub start --host-port 0.0.0.0:8085 --project=" + settings.ProjectID, - } + "gcloud beta emulators pubsub start --host-port 0.0.0.0:"+defaultPortNumber+" --project="+settings.ProjectID, + )) - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run pubsub: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "8085/tcp", "") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort, "") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } From 2dd11242338017356e3a271d70d7e32e1cddfa88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:38:29 +0200 Subject: [PATCH 08/11] chore(spanner): use Run function --- modules/gcloud/spanner/spanner.go | 33 +++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/modules/gcloud/spanner/spanner.go b/modules/gcloud/spanner/spanner.go index 388c6e5074..ac8af92ba9 100644 --- a/modules/gcloud/spanner/spanner.go +++ b/modules/gcloud/spanner/spanner.go @@ -10,7 +10,9 @@ import ( const ( // DefaultProjectID is the default project ID for the Pubsub container. - DefaultProjectID = "test-project" + DefaultProjectID = "test-project" + defaultPortNumber = "9010" + defaultPort = defaultPortNumber + "/tcp" ) // Container represents the Spanner container type used in the module @@ -32,16 +34,12 @@ func (c *Container) URI() string { // Run creates an instance of the Spanner GCloud container type. // The URI uses the empty string as the protocol. func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - req := testcontainers.GenericContainerRequest{ - ContainerRequest: testcontainers.ContainerRequest{ - Image: img, - ExposedPorts: []string{"9010/tcp"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("9010/tcp"), - wait.ForLog("Cloud Spanner emulator running"), - ), - }, - Started: true, + moduleOpts := []testcontainers.ContainerCustomizer{ + testcontainers.WithExposedPorts(defaultPort), + testcontainers.WithWaitStrategy(wait.ForAll( + wait.ForListeningPort(defaultPort), + wait.ForLog("Cloud Spanner emulator running"), + )), } settings := defaultOptions() @@ -51,21 +49,18 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, err } } - if err := opt.Customize(&req); err != nil { - return nil, err - } } - container, err := testcontainers.GenericContainer(ctx, req) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container - if container != nil { - c = &Container{Container: container, settings: settings} + if ctr != nil { + c = &Container{Container: ctr, settings: settings} } if err != nil { - return c, fmt.Errorf("generic container: %w", err) + return c, fmt.Errorf("run spanner: %w", err) } - portEndpoint, err := c.PortEndpoint(ctx, "9010/tcp", "") + portEndpoint, err := c.PortEndpoint(ctx, defaultPort, "") if err != nil { return c, fmt.Errorf("port endpoint: %w", err) } From 89fd448b52480243ebb36ed2af2bff50f3ca44a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:53:22 +0200 Subject: [PATCH 09/11] fix: missing options after refactor --- modules/gcloud/pubsub/pubsub.go | 2 ++ modules/gcloud/spanner/spanner.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/gcloud/pubsub/pubsub.go b/modules/gcloud/pubsub/pubsub.go index 8712ddb4dc..d3d0739a34 100644 --- a/modules/gcloud/pubsub/pubsub.go +++ b/modules/gcloud/pubsub/pubsub.go @@ -57,6 +57,8 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom "gcloud beta emulators pubsub start --host-port 0.0.0.0:"+defaultPortNumber+" --project="+settings.ProjectID, )) + moduleOpts = append(moduleOpts, opts...) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container if ctr != nil { diff --git a/modules/gcloud/spanner/spanner.go b/modules/gcloud/spanner/spanner.go index ac8af92ba9..22c093d35a 100644 --- a/modules/gcloud/spanner/spanner.go +++ b/modules/gcloud/spanner/spanner.go @@ -51,6 +51,8 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom } } + moduleOpts = append(moduleOpts, opts...) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container if ctr != nil { From 74e2656335a6870c060909a0464b3a40f9d0121d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:54:49 +0200 Subject: [PATCH 10/11] fix: typo in docs --- modules/gcloud/spanner/spanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/spanner/spanner.go b/modules/gcloud/spanner/spanner.go index 22c093d35a..7dbc618fe8 100644 --- a/modules/gcloud/spanner/spanner.go +++ b/modules/gcloud/spanner/spanner.go @@ -9,7 +9,7 @@ import ( ) const ( - // DefaultProjectID is the default project ID for the Pubsub container. + // DefaultProjectID is the default project ID for the Spanner container. DefaultProjectID = "test-project" defaultPortNumber = "9010" defaultPort = defaultPortNumber + "/tcp" From 15f5aa45fe5ed46b72077539fdca8e07d195b8c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Fri, 3 Oct 2025 07:56:43 +0200 Subject: [PATCH 11/11] fix: order --- modules/gcloud/bigquery/bigquery.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gcloud/bigquery/bigquery.go b/modules/gcloud/bigquery/bigquery.go index 2f9291ec8d..31faf282b7 100644 --- a/modules/gcloud/bigquery/bigquery.go +++ b/modules/gcloud/bigquery/bigquery.go @@ -60,10 +60,10 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom } } - moduleOpts = append(moduleOpts, opts...) - moduleOpts = append(moduleOpts, testcontainers.WithCmdArgs("--project", settings.ProjectID)) + moduleOpts = append(moduleOpts, opts...) + ctr, err := testcontainers.Run(ctx, img, moduleOpts...) var c *Container if ctr != nil {