From bfa2cb47fe53844f0f8c585f40815e43786822c1 Mon Sep 17 00:00:00 2001 From: Michael Ellis Date: Tue, 30 Apr 2024 23:34:40 +0000 Subject: [PATCH 01/19] Update bigquery container to have an optional seed yaml file --- modules/gcloud/bigquery.go | 12 +++-- modules/gcloud/bigquery_test.go | 87 +++++++++++++++++++++++++++++-- modules/gcloud/gcloud.go | 22 +++++++- modules/gcloud/go.mod | 4 ++ modules/gcloud/go.sum | 11 +++- modules/gcloud/testdata/data.yaml | 20 +++++++ 6 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 modules/gcloud/testdata/data.yaml diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index fe93f54485..75e047e5a9 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -13,7 +13,7 @@ import ( func RunBigQueryContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*GCloudContainer, error) { req := testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "ghcr.io/goccy/bigquery-emulator:0.4.3", + Image: "ghcr.io/goccy/bigquery-emulator:0.6.1", ExposedPorts: []string{"9050/tcp", "9060/tcp"}, WaitingFor: wait.ForHTTP("/discovery/v1/apis/bigquery/v2/rest").WithPort("9050/tcp").WithStartupTimeout(time.Second * 5), }, @@ -27,18 +27,22 @@ func RunBigQueryContainer(ctx context.Context, opts ...testcontainers.ContainerC req.Cmd = []string{"--project", settings.ProjectID} + for _, opt := range opts { + opt.Customize(&req) + } + container, err := testcontainers.GenericContainer(ctx, req) if err != nil { return nil, err } - spannerContainer, err := newGCloudContainer(ctx, 9050, container, settings) + bigqueryContainer, err := newGCloudContainer(ctx, 9050, container, settings) if err != nil { return nil, err } // always prepend http:// to the URI - spannerContainer.URI = "http://" + spannerContainer.URI + bigqueryContainer.URI = "http://" + bigqueryContainer.URI - return spannerContainer, nil + return bigqueryContainer, nil } diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 08bbd46a3a..1e06a66117 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "log" + "path/filepath" + "testing" "cloud.google.com/go/bigquery" "google.golang.org/api/iterator" @@ -13,17 +15,19 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/gcloud" ) -func ExampleRunBigQueryContainer() { +func TestBigQueryContainer(t *testing.T) { // runBigQueryContainer { ctx := context.Background() bigQueryContainer, err := gcloud.RunBigQueryContainer( ctx, - testcontainers.WithImage("ghcr.io/goccy/bigquery-emulator:0.4.3"), + testcontainers.WithImage("ghcr.io/goccy/bigquery-emulator:0.6.1"), gcloud.WithProjectID("bigquery-project"), ) if err != nil { @@ -78,8 +82,85 @@ func ExampleRunBigQueryContainer() { } } - fmt.Println(val) + // Output: + // [30] + expectedValue := int64(30) + actualValue := val[0] + fmt.Println(val[0]) + + require.NoError(t, err) + if assert.NotNil(t, val) { + assert.Equal(t, expectedValue, actualValue) + } +} + +func TestBigQueryWithDataYamlFile(t *testing.T) { + // runBigQueryContainer { + ctx := context.Background() + + absPath, err := filepath.Abs(filepath.Join(".", "testdata", "data.yaml")) + if err != nil { + log.Fatalf("failed to run container: %v", err) + } + + bigQueryContainer, err := gcloud.RunBigQueryContainer( + ctx, + testcontainers.WithImage("ghcr.io/goccy/bigquery-emulator:0.6.1"), + gcloud.WithProjectID("test"), + gcloud.WithDataYamlFile(absPath), + ) + if err != nil { + log.Fatalf("failed to run container: %v", err) + } + + // Clean up the container + defer func() { + if err := bigQueryContainer.Terminate(ctx); err != nil { + log.Fatalf("failed to terminate container: %v", err) + } + }() + // } + + // bigQueryClient { + projectID := bigQueryContainer.Settings.ProjectID + + opts := []option.ClientOption{ + option.WithEndpoint(bigQueryContainer.URI), + option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), + option.WithoutAuthentication(), + internaloption.SkipDialSettingsValidation(), + } + + client, err := bigquery.NewClient(ctx, projectID, opts...) + if err != nil { + log.Fatalf("failed to create bigquery client: %v", err) // nolint:gocritic + } + defer client.Close() + // } + + selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") + selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ + {Name: "name", Value: "bob"}, + } + it, err := selectQuery.Read(ctx) + if err != nil { + log.Fatalf("failed to read query: %v", err) + } + + var val []bigquery.Value + for { + err := it.Next(&val) + if errors.Is(err, iterator.Done) { + break + } + if err != nil { + log.Fatalf("failed to iterate: %v", err) + } + } // Output: // [30] + expectedValue := int64(30) + actualValue := val[0] + assert.Equal(t, expectedValue, actualValue) } diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index a5886dc743..3814c9ab72 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -41,12 +41,14 @@ func newGCloudContainer(ctx context.Context, port int, c testcontainers.Containe } type options struct { - ProjectID string + ProjectID string + DataYamlFile string } func defaultOptions() options { return options{ - ProjectID: defaultProjectID, + ProjectID: defaultProjectID, + DataYamlFile: "/data.yaml", } } @@ -69,6 +71,22 @@ func WithProjectID(projectID string) Option { } } +// WithDataYamlFile seeds the Bigquery project for the GCloud container. +func WithDataYamlFile(dataYamlFile string) testcontainers.CustomizeRequestOption { + return func(req *testcontainers.GenericContainerRequest) error { + dataFile := testcontainers.ContainerFile{ + HostFilePath: dataYamlFile, + ContainerFilePath: "/data.yaml", + FileMode: 0o755, + } + + req.Files = append(req.Files, dataFile) + req.Cmd = append(req.Cmd, "--data-from-yaml", "/data.yaml") + + return nil + } +} + // applyOptions applies the options to the container request and returns the settings. func applyOptions(req *testcontainers.GenericContainerRequest, opts []testcontainers.ContainerCustomizer) (options, error) { settings := defaultOptions() diff --git a/modules/gcloud/go.mod b/modules/gcloud/go.mod index 1e3f2a7932..b83a320ae4 100644 --- a/modules/gcloud/go.mod +++ b/modules/gcloud/go.mod @@ -10,6 +10,7 @@ require ( cloud.google.com/go/pubsub v1.36.2 cloud.google.com/go/spanner v1.57.0 github.com/docker/go-connections v0.5.0 + github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.30.0 google.golang.org/api v0.168.0 google.golang.org/grpc v1.62.0 @@ -34,6 +35,7 @@ require ( github.com/containerd/containerd v1.7.15 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/docker v25.0.5+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect @@ -68,6 +70,7 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect @@ -97,6 +100,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/testcontainers/testcontainers-go => ../.. diff --git a/modules/gcloud/go.sum b/modules/gcloud/go.sum index eaafc17e50..a4617b7a1d 100644 --- a/modules/gcloud/go.sum +++ b/modules/gcloud/go.sum @@ -149,6 +149,10 @@ github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGC github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -181,6 +185,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -191,8 +197,9 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -362,6 +369,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/modules/gcloud/testdata/data.yaml b/modules/gcloud/testdata/data.yaml new file mode 100644 index 0000000000..262f8ad5e2 --- /dev/null +++ b/modules/gcloud/testdata/data.yaml @@ -0,0 +1,20 @@ +projects: + - id: test + datasets: + - id: dataset1 + tables: + - id: table_a + columns: + - name: id + type: INTEGER + - name: name + type: STRING + - name: createdAt + type: TIMESTAMP + data: + - id: 1 + name: alice + createdAt: "2022-10-21T00:00:00" + - id: 30 + name: bob + createdAt: "2022-10-21T00:00:00" From 9d940cc5fb5fab4fe472bc52a409395664a7cf06 Mon Sep 17 00:00:00 2001 From: Michael Ellis Date: Wed, 1 May 2024 12:55:15 +0000 Subject: [PATCH 02/19] update opts snippet to handle error; update documentation --- docs/modules/gcloud.md | 13 ++++++++++++- modules/gcloud/bigquery.go | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index a925a9be66..08d17f362f 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -17,7 +17,7 @@ go get github.com/testcontainers/testcontainers-go/modules/gcloud ## Usage example !!!info - By default, the all the emulators use `gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators` as the default Docker image, except for the BigQuery emulator, which uses `ghcr.io/goccy/bigquery-emulator:0.4.3`, and Spanner, which uses `gcr.io/cloud-spanner-emulator/emulator:1.4.0`. + By default, the all the emulators use `gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators` as the default Docker image, except for the BigQuery emulator, which uses `ghcr.io/goccy/bigquery-emulator:0.6.1`, and Spanner, which uses `gcr.io/cloud-spanner-emulator/emulator:1.4.0`. ### BigQuery @@ -28,6 +28,17 @@ go get github.com/testcontainers/testcontainers-go/modules/gcloud It's important to set the `option.WithEndpoint()` option using the container's URI, as shown in the client example above. +#### Data Yaml (Seed File) + +If you would like to do additional initialization in the BigQuery container, add a `data.yaml` file to the container request with the `WithDataYamlFile` function. +Those files will be copied after the container is created but before it's started. The startup command then used will look like `--project test --data-from-yaml /data.yaml`. + +An example of a `data.yaml` file that seeds the BigQuery instance with datasets and tables is shown below: + + +[Data Yaml content](../../modules/gcloud/testdata/data.yaml) + + ### BigTable diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index 75e047e5a9..aefbabfa2b 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -28,7 +28,9 @@ func RunBigQueryContainer(ctx context.Context, opts ...testcontainers.ContainerC req.Cmd = []string{"--project", settings.ProjectID} for _, opt := range opts { - opt.Customize(&req) + if err := opt.Customize(&req); err != nil { + return nil, err + } } container, err := testcontainers.GenericContainer(ctx, req) From 97cc547d3b9944502c907916e335a65941c1c04c Mon Sep 17 00:00:00 2001 From: Michael Ellis Date: Wed, 1 May 2024 18:03:54 +0000 Subject: [PATCH 03/19] Update based on feedback --- modules/gcloud/bigquery.go | 8 +------- modules/gcloud/bigquery_test.go | 24 ++++++------------------ modules/gcloud/go.mod | 5 +---- modules/gcloud/go.sum | 8 -------- 4 files changed, 8 insertions(+), 37 deletions(-) diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index aefbabfa2b..7a28313cba 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -25,13 +25,7 @@ func RunBigQueryContainer(ctx context.Context, opts ...testcontainers.ContainerC return nil, err } - req.Cmd = []string{"--project", settings.ProjectID} - - for _, opt := range opts { - if err := opt.Customize(&req); err != nil { - return nil, err - } - } + req.Cmd = append(req.Cmd, "--project", settings.ProjectID) container, err := testcontainers.GenericContainer(ctx, req) if err != nil { diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 1e06a66117..ad71bd0a2b 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -15,13 +15,11 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/gcloud" ) -func TestBigQueryContainer(t *testing.T) { +func ExampleRunBigQueryContainer() { // runBigQueryContainer { ctx := context.Background() @@ -82,20 +80,12 @@ func TestBigQueryContainer(t *testing.T) { } } - // Output: - // [30] - expectedValue := int64(30) - actualValue := val[0] fmt.Println(val[0]) - - require.NoError(t, err) - if assert.NotNil(t, val) { - assert.Equal(t, expectedValue, actualValue) - } + // Output: + // 30 } func TestBigQueryWithDataYamlFile(t *testing.T) { - // runBigQueryContainer { ctx := context.Background() absPath, err := filepath.Abs(filepath.Join(".", "testdata", "data.yaml")) @@ -113,15 +103,12 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { log.Fatalf("failed to run container: %v", err) } - // Clean up the container defer func() { if err := bigQueryContainer.Terminate(ctx); err != nil { log.Fatalf("failed to terminate container: %v", err) } }() - // } - // bigQueryClient { projectID := bigQueryContainer.Settings.ProjectID opts := []option.ClientOption{ @@ -136,7 +123,6 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { log.Fatalf("failed to create bigquery client: %v", err) // nolint:gocritic } defer client.Close() - // } selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ @@ -162,5 +148,7 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { // [30] expectedValue := int64(30) actualValue := val[0] - assert.Equal(t, expectedValue, actualValue) + if expectedValue != actualValue { + t.Errorf("BigQuery value didn't match. \nExpected %v, \nbut got: %v", expectedValue, actualValue) + } } diff --git a/modules/gcloud/go.mod b/modules/gcloud/go.mod index b83a320ae4..1bb0e472d9 100644 --- a/modules/gcloud/go.mod +++ b/modules/gcloud/go.mod @@ -10,7 +10,6 @@ require ( cloud.google.com/go/pubsub v1.36.2 cloud.google.com/go/spanner v1.57.0 github.com/docker/go-connections v0.5.0 - github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.30.0 google.golang.org/api v0.168.0 google.golang.org/grpc v1.62.0 @@ -35,7 +34,6 @@ require ( github.com/containerd/containerd v1.7.15 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/docker v25.0.5+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect @@ -70,11 +68,11 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect @@ -100,7 +98,6 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78 // indirect google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) replace github.com/testcontainers/testcontainers-go => ../.. diff --git a/modules/gcloud/go.sum b/modules/gcloud/go.sum index a4617b7a1d..90c138a945 100644 --- a/modules/gcloud/go.sum +++ b/modules/gcloud/go.sum @@ -149,10 +149,6 @@ github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGC github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -185,8 +181,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -369,8 +363,6 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 1a70398bbd80552039b50e4f91b3b995599dd596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 11:15:12 +0100 Subject: [PATCH 04/19] chore: use new API for running big query container --- modules/gcloud/bigquery_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index f03a00f830..9706f90190 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -96,9 +96,9 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { log.Fatalf("failed to run container: %v", err) } - bigQueryContainer, err := gcloud.RunBigQueryContainer( + bigQueryContainer, err := gcloud.RunBigQuery( ctx, - testcontainers.WithImage("ghcr.io/goccy/bigquery-emulator:0.6.1"), + "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), gcloud.WithDataYamlFile(absPath), ) From c976be964d5eaf6a60e4835a17d9d4607f20c116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 11:15:39 +0100 Subject: [PATCH 05/19] chore: run make lint --- modules/gcloud/bigquery_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 9706f90190..f9dedc3a58 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -123,7 +123,7 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { client, err := bigquery.NewClient(ctx, projectID, opts...) if err != nil { - log.Fatalf("failed to create bigquery client: %v", err) // nolint:gocritic + log.Fatalf("failed to create bigquery client: %v", err) //nolint:gocritic } defer client.Close() From b22328432fd5aed937a9a057f4f1a0295c048dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 11:23:18 +0100 Subject: [PATCH 06/19] chore: use testify's require --- modules/gcloud/bigquery_test.go | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index f9dedc3a58..f6f22b0877 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -9,6 +9,7 @@ import ( "testing" "cloud.google.com/go/bigquery" + "github.com/stretchr/testify/require" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" @@ -92,9 +93,7 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { ctx := context.Background() absPath, err := filepath.Abs(filepath.Join(".", "testdata", "data.yaml")) - if err != nil { - log.Fatalf("failed to run container: %v", err) - } + require.NoError(t, err) bigQueryContainer, err := gcloud.RunBigQuery( ctx, @@ -102,15 +101,8 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { gcloud.WithProjectID("test"), gcloud.WithDataYamlFile(absPath), ) - if err != nil { - log.Fatalf("failed to run container: %v", err) - } - - defer func() { - if err := bigQueryContainer.Terminate(ctx); err != nil { - log.Fatalf("failed to terminate container: %v", err) - } - }() + testcontainers.CleanupContainer(t, bigQueryContainer) + require.NoError(t, err) projectID := bigQueryContainer.Settings.ProjectID @@ -122,9 +114,7 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { } client, err := bigquery.NewClient(ctx, projectID, opts...) - if err != nil { - log.Fatalf("failed to create bigquery client: %v", err) //nolint:gocritic - } + require.NoError(t, err) defer client.Close() selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") @@ -132,9 +122,7 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { {Name: "name", Value: "bob"}, } it, err := selectQuery.Read(ctx) - if err != nil { - log.Fatalf("failed to read query: %v", err) - } + require.NoError(t, err) var val []bigquery.Value for { @@ -142,16 +130,12 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { if errors.Is(err, iterator.Done) { break } - if err != nil { - log.Fatalf("failed to iterate: %v", err) - } + require.NoError(t, err) } // Output: // [30] expectedValue := int64(30) actualValue := val[0] - if expectedValue != actualValue { - t.Errorf("BigQuery value didn't match. \nExpected %v, \nbut got: %v", expectedValue, actualValue) - } + require.Equal(t, expectedValue, actualValue) } From 1e88a8b1d4e58c11a073e9462ce75729a0b29adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 11:25:21 +0100 Subject: [PATCH 07/19] chore: remove unused --- modules/gcloud/gcloud.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index d88194ffc2..5f7fa3ffec 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -44,14 +44,12 @@ func newGCloudContainer(ctx context.Context, req testcontainers.GenericContainer } type options struct { - ProjectID string - DataYamlFile string + ProjectID string } func defaultOptions() options { return options{ - ProjectID: defaultProjectID, - DataYamlFile: "/data.yaml", + ProjectID: defaultProjectID, } } From 0c4394a18359756c336b49e053a08a972185d1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 12:05:12 +0100 Subject: [PATCH 08/19] fix: process yaml file just once --- docs/modules/gcloud.md | 5 +++ modules/gcloud/bigquery.go | 14 ++++++ modules/gcloud/bigquery_test.go | 69 +++++++++++++++++++++++++++--- modules/gcloud/gcloud.go | 20 +++------ modules/gcloud/testdata/data2.yaml | 20 +++++++++ 5 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 modules/gcloud/testdata/data2.yaml diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 7a58c52388..6145c631eb 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -30,6 +30,8 @@ It's important to set the `option.WithEndpoint()` option using the container's U #### Data Yaml (Seed File) +- Not available until the next release of testcontainers-go :material-tag: main + If you would like to do additional initialization in the BigQuery container, add a `data.yaml` file to the container request with the `WithDataYamlFile` function. Those files will be copied after the container is created but before it's started. The startup command then used will look like `--project test --data-from-yaml /data.yaml`. @@ -39,6 +41,9 @@ An example of a `data.yaml` file that seeds the BigQuery instance with datasets [Data Yaml content](../../modules/gcloud/testdata/data.yaml) +!!!warning + This feature is only available for the `BigQuery` container, and if you pass multiple `WithDataYamlFile` options, the last file is used. + ### BigTable diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index 60b206d2ef..8f46358cac 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -2,6 +2,7 @@ package gcloud import ( "context" + "path/filepath" "time" "github.com/testcontainers/testcontainers-go" @@ -33,5 +34,18 @@ func RunBigQuery(ctx context.Context, img string, opts ...testcontainers.Contain req.Cmd = append(req.Cmd, "--project", settings.ProjectID) + // Process data yaml file only for the BigQuery container. + if settings.bigQueryDataYamlFile != "" { + containerPath := "/" + filepath.Base(settings.bigQueryDataYamlFile) + + req.Cmd = append(req.Cmd, "--data-from-yaml", containerPath) + + req.Files = append(req.Files, testcontainers.ContainerFile{ + HostFilePath: settings.bigQueryDataYamlFile, + ContainerFilePath: containerPath, + FileMode: 0o755, + }) + } + return newGCloudContainer(ctx, req, 9050, settings, "http://") } diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index f6f22b0877..7870fed52d 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -92,14 +92,14 @@ func ExampleRunBigQueryContainer() { func TestBigQueryWithDataYamlFile(t *testing.T) { ctx := context.Background() - absPath, err := filepath.Abs(filepath.Join(".", "testdata", "data.yaml")) + testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) require.NoError(t, err) bigQueryContainer, err := gcloud.RunBigQuery( ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYamlFile(absPath), + gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data.yaml")), ) testcontainers.CleanupContainer(t, bigQueryContainer) require.NoError(t, err) @@ -133,9 +133,64 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { require.NoError(t, err) } - // Output: - // [30] - expectedValue := int64(30) - actualValue := val[0] - require.Equal(t, expectedValue, actualValue) + require.Equal(t, int64(30), val[0]) +} + +func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { + ctx := context.Background() + + testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) + require.NoError(t, err) + + bigQueryContainer, err := gcloud.RunBigQuery( + ctx, + "ghcr.io/goccy/bigquery-emulator:0.6.1", + gcloud.WithProjectID("test"), + gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data.yaml")), + gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data2.yaml")), // last file will be used + ) + testcontainers.CleanupContainer(t, bigQueryContainer) + require.NoError(t, err) + + projectID := bigQueryContainer.Settings.ProjectID + + opts := []option.ClientOption{ + option.WithEndpoint(bigQueryContainer.URI), + option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), + option.WithoutAuthentication(), + internaloption.SkipDialSettingsValidation(), + } + + client, err := bigquery.NewClient(ctx, projectID, opts...) + require.NoError(t, err) + defer client.Close() + + t.Run("select/dataset1-not-found", func(t *testing.T) { + selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") + selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ + {Name: "name", Value: "bob"}, + } + _, err := selectQuery.Read(ctx) + require.Error(t, err) + }) + + t.Run("select/dataset2", func(t *testing.T) { + selectQuery := client.Query("SELECT * FROM dataset2.table_b where name = @name") + selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ + {Name: "name", Value: "naomi"}, + } + it, err := selectQuery.Read(ctx) + require.NoError(t, err) + + var val []bigquery.Value + for { + err := it.Next(&val) + if errors.Is(err, iterator.Done) { + break + } + require.NoError(t, err) + } + + require.Equal(t, int64(60), val[0]) + }) } diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index 5f7fa3ffec..67fce740a3 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -44,7 +44,8 @@ func newGCloudContainer(ctx context.Context, req testcontainers.GenericContainer } type options struct { - ProjectID string + ProjectID string + bigQueryDataYamlFile string } func defaultOptions() options { @@ -73,18 +74,11 @@ func WithProjectID(projectID string) Option { } // WithDataYamlFile seeds the Bigquery project for the GCloud container. -func WithDataYamlFile(dataYamlFile string) testcontainers.CustomizeRequestOption { - return func(req *testcontainers.GenericContainerRequest) error { - dataFile := testcontainers.ContainerFile{ - HostFilePath: dataYamlFile, - ContainerFilePath: "/data.yaml", - FileMode: 0o755, - } - - req.Files = append(req.Files, dataFile) - req.Cmd = append(req.Cmd, "--data-from-yaml", "/data.yaml") - - return nil +// Other GCloud containers will ignore this option. +// If this option is passed multiple times, the last file will be used. +func WithDataYamlFile(dataYamlFile string) Option { + return func(o *options) { + o.bigQueryDataYamlFile = dataYamlFile } } diff --git a/modules/gcloud/testdata/data2.yaml b/modules/gcloud/testdata/data2.yaml new file mode 100644 index 0000000000..5856278a5c --- /dev/null +++ b/modules/gcloud/testdata/data2.yaml @@ -0,0 +1,20 @@ +projects: + - id: test + datasets: + - id: dataset2 + tables: + - id: table_b + columns: + - name: id + type: INTEGER + - name: name + type: STRING + - name: createdAt + type: TIMESTAMP + data: + - id: 1 + name: mike + createdAt: "2022-10-21T00:00:00" + - id: 60 + name: naomi + createdAt: "2022-10-21T00:00:00" From f7c3264fcef8cc46a6fc1116d3e830b6bde06797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 12:42:14 +0100 Subject: [PATCH 09/19] chore: rename variable --- modules/gcloud/gcloud.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index 67fce740a3..523cbd6a43 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -73,12 +73,15 @@ func WithProjectID(projectID string) Option { } } -// WithDataYamlFile seeds the Bigquery project for the GCloud container. +// WithDataYamlFile seeds the Bigquery project for the GCloud container +// with the local path to the data yaml file, which is used to copy the file to the container, +// and then process the file to seed the Bigquery project. +// // Other GCloud containers will ignore this option. // If this option is passed multiple times, the last file will be used. -func WithDataYamlFile(dataYamlFile string) Option { +func WithDataYamlFile(f string) Option { return func(o *options) { - o.bigQueryDataYamlFile = dataYamlFile + o.bigQueryDataYamlFile = f } } From 2956a1099a16c23af604290cffc1e8985a7e98ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 12:42:53 +0100 Subject: [PATCH 10/19] chore: run mod tidy --- modules/gcloud/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/gcloud/go.mod b/modules/gcloud/go.mod index 5c05fce458..550be3a19b 100644 --- a/modules/gcloud/go.mod +++ b/modules/gcloud/go.mod @@ -10,6 +10,7 @@ require ( cloud.google.com/go/pubsub v1.36.2 cloud.google.com/go/spanner v1.57.0 github.com/docker/go-connections v0.5.0 + github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.34.0 google.golang.org/api v0.169.0 google.golang.org/grpc v1.64.1 @@ -74,7 +75,6 @@ require ( github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/stretchr/testify v1.9.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect From cd8324c56bd063c1fca563545f994d5d2166dcf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 14:33:58 +0100 Subject: [PATCH 11/19] chore: pass a reader to WithDataYAML option --- docs/modules/gcloud.md | 8 ++++---- modules/gcloud/bigquery.go | 9 ++++----- modules/gcloud/bigquery_test.go | 16 +++++++++++++--- modules/gcloud/gcloud.go | 17 +++++++++-------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 6145c631eb..2344ebc393 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -28,12 +28,12 @@ go get github.com/testcontainers/testcontainers-go/modules/gcloud It's important to set the `option.WithEndpoint()` option using the container's URI, as shown in the client example above. -#### Data Yaml (Seed File) +#### Data YAML (Seed File) - Not available until the next release of testcontainers-go :material-tag: main -If you would like to do additional initialization in the BigQuery container, add a `data.yaml` file to the container request with the `WithDataYamlFile` function. -Those files will be copied after the container is created but before it's started. The startup command then used will look like `--project test --data-from-yaml /data.yaml`. +If you would like to do additional initialization in the BigQuery container, add a `data.yaml` file represented by an `io.Reader` to the container request with the `WithDataYAML` function. +That file is copied after the container is created but before it's started. The startup command then used will look like `--project test --data-from-yaml /testcontainers-data.yaml`. An example of a `data.yaml` file that seeds the BigQuery instance with datasets and tables is shown below: @@ -42,7 +42,7 @@ An example of a `data.yaml` file that seeds the BigQuery instance with datasets !!!warning - This feature is only available for the `BigQuery` container, and if you pass multiple `WithDataYamlFile` options, the last file is used. + This feature is only available for the `BigQuery` container, and if you pass multiple `WithDataYAML` options, only the last one is used. ### BigTable diff --git a/modules/gcloud/bigquery.go b/modules/gcloud/bigquery.go index 8f46358cac..6e6d7627dc 100644 --- a/modules/gcloud/bigquery.go +++ b/modules/gcloud/bigquery.go @@ -2,7 +2,6 @@ package gcloud import ( "context" - "path/filepath" "time" "github.com/testcontainers/testcontainers-go" @@ -35,15 +34,15 @@ func RunBigQuery(ctx context.Context, img string, opts ...testcontainers.Contain req.Cmd = append(req.Cmd, "--project", settings.ProjectID) // Process data yaml file only for the BigQuery container. - if settings.bigQueryDataYamlFile != "" { - containerPath := "/" + filepath.Base(settings.bigQueryDataYamlFile) + if settings.bigQueryDataYaml != nil { + containerPath := "/testcontainers-data.yaml" req.Cmd = append(req.Cmd, "--data-from-yaml", containerPath) req.Files = append(req.Files, testcontainers.ContainerFile{ - HostFilePath: settings.bigQueryDataYamlFile, + Reader: settings.bigQueryDataYaml, ContainerFilePath: containerPath, - FileMode: 0o755, + FileMode: 0o644, }) } diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 7870fed52d..a9b73271ed 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log" + "os" "path/filepath" "testing" @@ -95,11 +96,14 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) require.NoError(t, err) + r, err := os.Open(filepath.Join(testDataPath, "data.yaml")) + require.NoError(t, err) + bigQueryContainer, err := gcloud.RunBigQuery( ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data.yaml")), + gcloud.WithDataYAML(r), ) testcontainers.CleanupContainer(t, bigQueryContainer) require.NoError(t, err) @@ -142,12 +146,18 @@ func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) require.NoError(t, err) + r1, err := os.Open(filepath.Join(testDataPath, "data.yaml")) + require.NoError(t, err) + + r2, err := os.Open(filepath.Join(testDataPath, "data2.yaml")) + require.NoError(t, err) + bigQueryContainer, err := gcloud.RunBigQuery( ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data.yaml")), - gcloud.WithDataYamlFile(filepath.Join(testDataPath, "data2.yaml")), // last file will be used + gcloud.WithDataYAML(r1), + gcloud.WithDataYAML(r2), // last file will be used ) testcontainers.CleanupContainer(t, bigQueryContainer) require.NoError(t, err) diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index 523cbd6a43..1f03c6ed30 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -3,6 +3,7 @@ package gcloud import ( "context" "fmt" + "io" "github.com/docker/go-connections/nat" @@ -44,8 +45,8 @@ func newGCloudContainer(ctx context.Context, req testcontainers.GenericContainer } type options struct { - ProjectID string - bigQueryDataYamlFile string + ProjectID string + bigQueryDataYaml io.Reader } func defaultOptions() options { @@ -73,15 +74,15 @@ func WithProjectID(projectID string) Option { } } -// WithDataYamlFile seeds the Bigquery project for the GCloud container -// with the local path to the data yaml file, which is used to copy the file to the container, -// and then process the file to seed the Bigquery project. +// WithDataYAML seeds the Bigquery project for the GCloud container with an io.Reader representing +// the data yaml file, which is used to copy the file to the container, and then processed to seed +// the Bigquery project. // // Other GCloud containers will ignore this option. -// If this option is passed multiple times, the last file will be used. -func WithDataYamlFile(f string) Option { +// If this option is passed multiple times, the last added will be used. +func WithDataYAML(r io.Reader) Option { return func(o *options) { - o.bigQueryDataYamlFile = f + o.bigQueryDataYaml = r } } From f4470095b3d21ed4373065dbd0e0cf172a37cca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 17:06:55 +0100 Subject: [PATCH 12/19] chore: do not allow multiple calls to WithDataYAML --- docs/modules/gcloud.md | 2 +- modules/gcloud/bigquery_test.go | 44 +-------------------------------- modules/gcloud/gcloud.go | 17 ++++++++++--- 3 files changed, 15 insertions(+), 48 deletions(-) diff --git a/docs/modules/gcloud.md b/docs/modules/gcloud.md index 2344ebc393..92135102ff 100644 --- a/docs/modules/gcloud.md +++ b/docs/modules/gcloud.md @@ -42,7 +42,7 @@ An example of a `data.yaml` file that seeds the BigQuery instance with datasets !!!warning - This feature is only available for the `BigQuery` container, and if you pass multiple `WithDataYAML` options, only the last one is used. + This feature is only available for the `BigQuery` container, and if you pass multiple `WithDataYAML` options, an error is returned. ### BigTable diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index a9b73271ed..7a09276a95 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -160,47 +160,5 @@ func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { gcloud.WithDataYAML(r2), // last file will be used ) testcontainers.CleanupContainer(t, bigQueryContainer) - require.NoError(t, err) - - projectID := bigQueryContainer.Settings.ProjectID - - opts := []option.ClientOption{ - option.WithEndpoint(bigQueryContainer.URI), - option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), - option.WithoutAuthentication(), - internaloption.SkipDialSettingsValidation(), - } - - client, err := bigquery.NewClient(ctx, projectID, opts...) - require.NoError(t, err) - defer client.Close() - - t.Run("select/dataset1-not-found", func(t *testing.T) { - selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") - selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ - {Name: "name", Value: "bob"}, - } - _, err := selectQuery.Read(ctx) - require.Error(t, err) - }) - - t.Run("select/dataset2", func(t *testing.T) { - selectQuery := client.Query("SELECT * FROM dataset2.table_b where name = @name") - selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ - {Name: "name", Value: "naomi"}, - } - it, err := selectQuery.Read(ctx) - require.NoError(t, err) - - var val []bigquery.Value - for { - err := it.Next(&val) - if errors.Is(err, iterator.Done) { - break - } - require.NoError(t, err) - } - - require.Equal(t, int64(60), val[0]) - }) + require.Error(t, err) } diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index 1f03c6ed30..281e6067d5 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -2,6 +2,7 @@ package gcloud import ( "context" + "errors" "fmt" "io" @@ -59,7 +60,7 @@ func defaultOptions() options { var _ testcontainers.ContainerCustomizer = (*Option)(nil) // Option is an option for the GCloud container. -type Option func(*options) +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 { @@ -69,8 +70,9 @@ func (o Option) Customize(*testcontainers.GenericContainerRequest) error { // WithProjectID sets the project ID for the GCloud container. func WithProjectID(projectID string) Option { - return func(o *options) { + return func(o *options) error { o.ProjectID = projectID + return nil } } @@ -81,8 +83,13 @@ func WithProjectID(projectID string) Option { // Other GCloud containers will ignore this option. // If this option is passed multiple times, the last added will be used. func WithDataYAML(r io.Reader) Option { - return func(o *options) { + return func(o *options) error { + if o.bigQueryDataYaml != nil { + return errors.New("data yaml file already exists") + } + o.bigQueryDataYaml = r + return nil } } @@ -91,7 +98,9 @@ func applyOptions(req *testcontainers.GenericContainerRequest, opts []testcontai settings := defaultOptions() for _, opt := range opts { if apply, ok := opt.(Option); ok { - apply(&settings) + if err := apply(&settings); err != nil { + return options{}, err + } } if err := opt.Customize(req); err != nil { return options{}, err From ebb3bb948d81719161b007da508b65bb86eccdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 11 Dec 2024 17:47:46 +0100 Subject: [PATCH 13/19] chore: embed test resource --- modules/gcloud/bigquery_test.go | 18 +++++++----------- modules/gcloud/testdata/data2.yaml | 20 -------------------- 2 files changed, 7 insertions(+), 31 deletions(-) delete mode 100644 modules/gcloud/testdata/data2.yaml diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 7a09276a95..68b36f46ea 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -2,11 +2,13 @@ package gcloud_test import ( "context" + _ "embed" "errors" "fmt" "log" "os" "path/filepath" + "strings" "testing" "cloud.google.com/go/bigquery" @@ -140,24 +142,18 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { require.Equal(t, int64(30), val[0]) } +//go:embed testdata/data.yaml +var dataYaml []byte + func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { ctx := context.Background() - testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) - require.NoError(t, err) - - r1, err := os.Open(filepath.Join(testDataPath, "data.yaml")) - require.NoError(t, err) - - r2, err := os.Open(filepath.Join(testDataPath, "data2.yaml")) - require.NoError(t, err) - bigQueryContainer, err := gcloud.RunBigQuery( ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYAML(r1), - gcloud.WithDataYAML(r2), // last file will be used + gcloud.WithDataYAML(strings.NewReader(string(dataYaml))), + gcloud.WithDataYAML(strings.NewReader(string(dataYaml))), // last file will cause an error ) testcontainers.CleanupContainer(t, bigQueryContainer) require.Error(t, err) diff --git a/modules/gcloud/testdata/data2.yaml b/modules/gcloud/testdata/data2.yaml deleted file mode 100644 index 5856278a5c..0000000000 --- a/modules/gcloud/testdata/data2.yaml +++ /dev/null @@ -1,20 +0,0 @@ -projects: - - id: test - datasets: - - id: dataset2 - tables: - - id: table_b - columns: - - name: id - type: INTEGER - - name: name - type: STRING - - name: createdAt - type: TIMESTAMP - data: - - id: 1 - name: mike - createdAt: "2022-10-21T00:00:00" - - id: 60 - name: naomi - createdAt: "2022-10-21T00:00:00" From c60982c142969cbe722a924397f510b8146c2a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 06:52:22 +0100 Subject: [PATCH 14/19] chore: simplify reader --- modules/gcloud/bigquery_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 68b36f46ea..d48633a2ae 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -1,6 +1,7 @@ package gcloud_test import ( + "bytes" "context" _ "embed" "errors" @@ -8,7 +9,6 @@ import ( "log" "os" "path/filepath" - "strings" "testing" "cloud.google.com/go/bigquery" @@ -152,8 +152,8 @@ func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYAML(strings.NewReader(string(dataYaml))), - gcloud.WithDataYAML(strings.NewReader(string(dataYaml))), // last file will cause an error + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), // last file will cause an error ) testcontainers.CleanupContainer(t, bigQueryContainer) require.Error(t, err) From 23539f48621676041aba7a32929b8f4a82ffced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 06:55:30 +0100 Subject: [PATCH 15/19] fix: update docs --- modules/gcloud/gcloud.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index 281e6067d5..d3c5354c7f 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -76,16 +76,16 @@ func WithProjectID(projectID string) Option { } } -// WithDataYAML seeds the Bigquery project for the GCloud container with an io.Reader representing +// WithDataYAML seeds the Bigquery project for the GCloud container with an [io.Reader] representing // the data yaml file, which is used to copy the file to the container, and then processed to seed // the Bigquery project. // // Other GCloud containers will ignore this option. -// If this option is passed multiple times, the last added will be used. +// If this option is passed multiple times, an error is returned. func WithDataYAML(r io.Reader) Option { return func(o *options) error { if o.bigQueryDataYaml != nil { - return errors.New("data yaml file already exists") + return errors.New("data yaml already exists") } o.bigQueryDataYaml = r From 0f33890dd8170bb42d5ba71a4592488a83a2440f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 06:55:44 +0100 Subject: [PATCH 16/19] chore: use the embed file even more --- modules/gcloud/bigquery_test.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index d48633a2ae..778636978b 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -7,8 +7,6 @@ import ( "errors" "fmt" "log" - "os" - "path/filepath" "testing" "cloud.google.com/go/bigquery" @@ -23,6 +21,9 @@ import ( "github.com/testcontainers/testcontainers-go/modules/gcloud" ) +//go:embed testdata/data.yaml +var dataYaml []byte + func ExampleRunBigQueryContainer() { // runBigQueryContainer { ctx := context.Background() @@ -95,17 +96,11 @@ func ExampleRunBigQueryContainer() { func TestBigQueryWithDataYamlFile(t *testing.T) { ctx := context.Background() - testDataPath, err := filepath.Abs(filepath.Join(".", "testdata")) - require.NoError(t, err) - - r, err := os.Open(filepath.Join(testDataPath, "data.yaml")) - require.NoError(t, err) - bigQueryContainer, err := gcloud.RunBigQuery( ctx, "ghcr.io/goccy/bigquery-emulator:0.6.1", gcloud.WithProjectID("test"), - gcloud.WithDataYAML(r), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), ) testcontainers.CleanupContainer(t, bigQueryContainer) require.NoError(t, err) @@ -142,9 +137,6 @@ func TestBigQueryWithDataYamlFile(t *testing.T) { require.Equal(t, int64(30), val[0]) } -//go:embed testdata/data.yaml -var dataYaml []byte - func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { ctx := context.Background() From a83f585067a46cf02b329dfc12d6a21f065ec13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 06:56:28 +0100 Subject: [PATCH 17/19] docs: wording --- modules/gcloud/gcloud.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gcloud/gcloud.go b/modules/gcloud/gcloud.go index d3c5354c7f..2b6a28ed5d 100644 --- a/modules/gcloud/gcloud.go +++ b/modules/gcloud/gcloud.go @@ -76,9 +76,9 @@ func WithProjectID(projectID string) Option { } } -// WithDataYAML seeds the Bigquery project for the GCloud container with an [io.Reader] representing +// WithDataYAML seeds the BigQuery project for the GCloud container with an [io.Reader] representing // the data yaml file, which is used to copy the file to the container, and then processed to seed -// the Bigquery project. +// the BigQuery project. // // Other GCloud containers will ignore this option. // If this option is passed multiple times, an error is returned. From 05f1ed94cccc55c776f349d9c17834ecdd5746b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 06:58:45 +0100 Subject: [PATCH 18/19] chore: simplify tests --- modules/gcloud/bigquery_test.go | 109 +++++++++++++++++++------------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 778636978b..20c21f375e 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -93,60 +93,79 @@ func ExampleRunBigQueryContainer() { // 30 } -func TestBigQueryWithDataYamlFile(t *testing.T) { +func TestBigQueryWithDataYAML(t *testing.T) { ctx := context.Background() - bigQueryContainer, err := gcloud.RunBigQuery( - ctx, - "ghcr.io/goccy/bigquery-emulator:0.6.1", - gcloud.WithProjectID("test"), - gcloud.WithDataYAML(bytes.NewReader(dataYaml)), - ) - testcontainers.CleanupContainer(t, bigQueryContainer) - require.NoError(t, err) + t.Run("valid", func(t *testing.T) { + bigQueryContainer, err := gcloud.RunBigQuery( + ctx, + "ghcr.io/goccy/bigquery-emulator:0.6.1", + gcloud.WithProjectID("test"), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), + ) + testcontainers.CleanupContainer(t, bigQueryContainer) + require.NoError(t, err) - projectID := bigQueryContainer.Settings.ProjectID + projectID := bigQueryContainer.Settings.ProjectID - opts := []option.ClientOption{ - option.WithEndpoint(bigQueryContainer.URI), - option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), - option.WithoutAuthentication(), - internaloption.SkipDialSettingsValidation(), - } - - client, err := bigquery.NewClient(ctx, projectID, opts...) - require.NoError(t, err) - defer client.Close() + opts := []option.ClientOption{ + option.WithEndpoint(bigQueryContainer.URI), + option.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())), + option.WithoutAuthentication(), + internaloption.SkipDialSettingsValidation(), + } - selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") - selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ - {Name: "name", Value: "bob"}, - } - it, err := selectQuery.Read(ctx) - require.NoError(t, err) + client, err := bigquery.NewClient(ctx, projectID, opts...) + require.NoError(t, err) + defer client.Close() - var val []bigquery.Value - for { - err := it.Next(&val) - if errors.Is(err, iterator.Done) { - break + selectQuery := client.Query("SELECT * FROM dataset1.table_a where name = @name") + selectQuery.QueryConfig.Parameters = []bigquery.QueryParameter{ + {Name: "name", Value: "bob"}, } + it, err := selectQuery.Read(ctx) require.NoError(t, err) - } - require.Equal(t, int64(30), val[0]) -} + var val []bigquery.Value + for { + err := it.Next(&val) + if errors.Is(err, iterator.Done) { + break + } + require.NoError(t, err) + } -func TestBigQueryWithDataYamlFile_multiple(t *testing.T) { - ctx := context.Background() + require.Equal(t, int64(30), val[0]) + }) + + t.Run("multi-value-set", func(t *testing.T) { + bigQueryContainer, err := gcloud.RunBigQuery( + ctx, + "ghcr.io/goccy/bigquery-emulator:0.6.1", + gcloud.WithProjectID("test"), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), + ) + testcontainers.CleanupContainer(t, bigQueryContainer) + require.EqualError(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 + } + } - bigQueryContainer, err := gcloud.RunBigQuery( - ctx, - "ghcr.io/goccy/bigquery-emulator:0.6.1", - gcloud.WithProjectID("test"), - gcloud.WithDataYAML(bytes.NewReader(dataYaml)), - gcloud.WithDataYAML(bytes.NewReader(dataYaml)), // last file will cause an error - ) - testcontainers.CleanupContainer(t, bigQueryContainer) - require.Error(t, err) + bigQueryContainer, err := gcloud.RunBigQuery( + ctx, + "ghcr.io/goccy/bigquery-emulator:0.6.1", + noValueOption(), // because --project is always added last, this option will receive `--project` as value, which results in an error + gcloud.WithProjectID("test"), + gcloud.WithDataYAML(bytes.NewReader(dataYaml)), + ) + testcontainers.CleanupContainer(t, bigQueryContainer) + require.Error(t, err) + }) } From 30e384a7272c898b588075c18154838a1f24e701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 12 Dec 2024 11:12:47 +0100 Subject: [PATCH 19/19] chore: use original assertion --- modules/gcloud/bigquery_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/gcloud/bigquery_test.go b/modules/gcloud/bigquery_test.go index 20c21f375e..221a750c2d 100644 --- a/modules/gcloud/bigquery_test.go +++ b/modules/gcloud/bigquery_test.go @@ -88,9 +88,9 @@ func ExampleRunBigQueryContainer() { } } - fmt.Println(val[0]) + fmt.Println(val) // Output: - // 30 + // [30] } func TestBigQueryWithDataYAML(t *testing.T) {