From 6d8d1c5c526882aa7454a1ba3acff3d3a87fa4c3 Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Fri, 10 Oct 2025 17:20:57 +0000 Subject: [PATCH 1/7] chore: Migrate kitchen -> cft --- .kitchen.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .kitchen.yml diff --git a/.kitchen.yml b/.kitchen.yml deleted file mode 100644 index a9626ee1..00000000 --- a/.kitchen.yml +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - ---- -provisioner: - name: terraform - -platforms: - - name: local - -verifier: - name: terraform - systems: - - name: system - backend: gcp - -suites: - - name: full - driver: - name: terraform - command_timeout: 1800 - root_module_directory: test/fixtures/full - # setting version verification to false since it requires TF to be less than v1.1 - verify_version: false From b60cb93c833847e1c5b6ea552f4c33a02a875236 Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Mon, 13 Oct 2025 19:09:23 +0000 Subject: [PATCH 2/7] wip --- Makefile | 2 +- build/int.cloudbuild.yaml | 14 +- .../data_warehouse/data_warehouse_test.go | 43 ++-- test/integration/full/controls/big_query.rb | 93 -------- test/integration/full/inspec.yml | 31 --- .../multiple_tables/multiple_tables_test.go | 202 ++++++++++++++++++ test/setup/main.tf | 14 +- 7 files changed, 235 insertions(+), 164 deletions(-) delete mode 100644 test/integration/full/controls/big_query.rb delete mode 100644 test/integration/full/inspec.yml create mode 100644 test/integration/multiple_tables/multiple_tables_test.go diff --git a/Makefile b/Makefile index 705770a0..75f060e5 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ docker_test_integration: -e SERVICE_ACCOUNT_JSON \ -v $(CURDIR):/workspace \ $(REGISTRY_URL)/${DOCKER_IMAGE_DEVELOPER_TOOLS}:${DOCKER_TAG_VERSION_DEVELOPER_TOOLS} \ - /usr/local/bin/test_integration.sh + cft test run all # Execute lint tests within the docker container .PHONY: docker_test_lint diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index f351305d..2869fdb4 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -24,19 +24,11 @@ steps: - 'TF_VAR_org_id=$_ORG_ID' - 'TF_VAR_folder_id=$_FOLDER_ID' - 'TF_VAR_billing_account=$_BILLING_ACCOUNT' -- id: create +- id: multiple-tables name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' - args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do create'] -- id: converge - name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' - args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do converge'] -- id: verify - name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' - args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do verify'] -- id: destroy - name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' - args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && kitchen_do destroy'] + args: ['/bin/bash', '-c', 'cft test run TestMultipleTables --verbose'] - id: create-dwh + waitFor: prepare name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'cft test run TestDataWarehouse --stage init --verbose'] - id: apply-dwh diff --git a/test/integration/data_warehouse/data_warehouse_test.go b/test/integration/data_warehouse/data_warehouse_test.go index b92be595..a3864cfd 100644 --- a/test/integration/data_warehouse/data_warehouse_test.go +++ b/test/integration/data_warehouse/data_warehouse_test.go @@ -66,28 +66,28 @@ func TestDataWarehouse(t *testing.T) { utils.Poll(t, verifyWorkflows, 8, 30*time.Second) homeDir, err := os.UserHomeDir() - if err != nil { - log.Fatal(err) - } - file, err := os.Create(homeDir + "/.bigqueryrc") - if err != nil { - log.Fatal(err) - } - file.Close() + if err != nil { + log.Fatal(err) + } + file, err := os.Create(homeDir + "/.bigqueryrc") + if err != nil { + log.Fatal(err) + } + file.Close() // Assert BigQuery tables & views are not empty - test_tables := func (){ + test_tables := func() { tables := []string{ - "thelook.distribution_centers", - "thelook.events", - "thelook.inventory_items", - "thelook.order_items", - "thelook.orders", - "thelook.products", - "thelook.users", - "thelook.lookerstudio_report_distribution_centers", - "thelook.lookerstudio_report_profit", + "thelook.distribution_centers", + "thelook.events", + "thelook.inventory_items", + "thelook.order_items", + "thelook.orders", + "thelook.products", + "thelook.users", + "thelook.lookerstudio_report_distribution_centers", + "thelook.lookerstudio_report_profit", } query_template := "SELECT COUNT(*) AS count_rows FROM `%[1]s.%[2]s`;" @@ -108,7 +108,6 @@ func TestDataWarehouse(t *testing.T) { // Assert BigQuery connection to Vertex GenAI was successfully created and works as expected test_llms := func() { - llm_query_template := "SELECT COUNT(*) AS count_rows FROM ML.GENERATE_TEXT(MODEL `%[1]s.thelook.text_generate_model`, (with clusters AS(SELECT CONCAT('cluster', CAST(centroid_id as STRING)) as centroid, avg_spend as average_spend, count_orders as count_of_orders, days_since_order FROM (SELECT centroid_id, feature, ROUND(numerical_value, 2) as value FROM ML.CENTROIDS(MODEL `%[1]s.thelook.customer_segment_clustering`)) PIVOT (SUM(value) FOR feature IN ('avg_spend', 'count_orders', 'days_since_order')) ORDER BY centroid_id) SELECT 'Pretend you are a creative strategist, given the following clusters come up with creative brand persona and title labels for each of these clusters, and explain step by step; what would be the next marketing step for these clusters' || ' ' || clusters.centroid || ', Average Spend $' || clusters.average_spend || ', Count of orders per person ' || clusters.count_of_orders || ', Days since last order ' || clusters.days_since_order AS prompt FROM clusters), STRUCT(800 AS max_output_tokens, 0.8 AS temperature, 40 AS top_k, 0.8 AS top_p, TRUE AS flatten_json_output));" query := fmt.Sprintf(llm_query_template, projectID) llm_op := bq.Runf(t, "--project_id=%[1]s --headless=true query --nouse_legacy_sql %[2]s", projectID, query) @@ -117,9 +116,9 @@ func TestDataWarehouse(t *testing.T) { count_llm_kind := reflect.TypeOf(llm_count).Kind() llm_test_result := assert.Greater(llm_count, int64(0)) if llm_test_result == true { - } else { - fmt.Printf("Some kind of error occurred while running the llm_count query. We think it has %[1]d rows. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[2]s \n Variable type for the count. This should be INT64: %[3]s \n ", llm_count, llm_op, count_llm_kind) - } + } else { + fmt.Printf("Some kind of error occurred while running the llm_count query. We think it has %[1]d rows. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[2]s \n Variable type for the count. This should be INT64: %[3]s \n ", llm_count, llm_op, count_llm_kind) + } } test_llms() }) diff --git a/test/integration/full/controls/big_query.rb b/test/integration/full/controls/big_query.rb deleted file mode 100644 index a1d5c385..00000000 --- a/test/integration/full/controls/big_query.rb +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Attributes can be used to create tests with as the mode becomes more complex -project_id = attribute('bigquery_dataset')[:project] -dataset_name = attribute('bigquery_dataset')[:friendly_name] -tables = attribute('bigquery_tables') -external_tables = attribute('bigquery_external_tables') - -describe google_bigquery_dataset(project: "#{project_id}", name: "#{dataset_name}") do - it { should exist } - - its('friendly_name') { should eq "#{dataset_name}" } - its('description') { should eq 'some description' } - its('location') { should eq 'US' } - its('default_table_expiration_ms') { should cmp '3600000' } - its('default_encryption_configuration.kms_key_name') { should cmp "projects/#{project_id}/locations/us/keyRings/ci-bigquery-keyring/cryptoKeys/foo" } -end - -describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:foo][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{tables[:foo][:friendly_name]}" } - its('time_partitioning.type') { should eq 'DAY' } - its('clustering') { should_not be nil } -end - -describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:bar][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{tables[:bar][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } -end - -describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:csv_example][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{external_tables[:csv_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('type') { should eq "EXTERNAL" } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "CSV" } - its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/bigquery-external-table-test.csv"] } - - its('external_data_configuration.csv_options.quote') { should eq "\"" } - its('external_data_configuration.csv_options.allow_jagged_rows') { should be nil } - its('external_data_configuration.csv_options.allow_quoted_newlines') { should be true } - its('external_data_configuration.csv_options.encoding') { should eq "UTF-8" } - its('external_data_configuration.csv_options.field_delimiter') { should eq "," } - its('external_data_configuration.csv_options.skip_leading_rows') { should eq "1" } -end - -describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:hive_example][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{external_tables[:hive_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('type') { should eq "EXTERNAL" } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "CSV" } - its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/hive_partition_example/year=2012/foo.csv","gs://ci-bq-external-data/hive_partition_example/year=2013/bar.csv"] } -end - -describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:google_sheets_example][:friendly_name]}") do - it { should exist } - its('type') { should eq "EXTERNAL" } - its('friendly_name') { should eq "#{external_tables[:google_sheets_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "GOOGLE_SHEETS" } - its('external_data_configuration.source_uris') { should eq ["https://docs.google.com/spreadsheets/d/15v4N2UG6bv1RmX__wru4Ei_mYMdVcM1MwRRLxFKc55s"] } - its('external_data_configuration.google_sheets_options.skip_leading_rows') { should eq "1" } -end diff --git a/test/integration/full/inspec.yml b/test/integration/full/inspec.yml deleted file mode 100644 index 471b9dd1..00000000 --- a/test/integration/full/inspec.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: local -depends: - - name: inspec-gcp - git: https://github.com/inspec/inspec-gcp.git - tag: v1.10.0 -supports: - - platform: gcp -attributes: - - name: bigquery_dataset - required: true - type: hash - - name: bigquery_tables - required: true - type: hash - - name: bigquery_external_tables - required: true - type: hash diff --git a/test/integration/multiple_tables/multiple_tables_test.go b/test/integration/multiple_tables/multiple_tables_test.go new file mode 100644 index 00000000..aaa62349 --- /dev/null +++ b/test/integration/multiple_tables/multiple_tables_test.go @@ -0,0 +1,202 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package multiple_tables + +import ( + "fmt" + "log" + "os" + "reflect" + "strings" + "testing" + "time" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/bq" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/utils" + "github.com/stretchr/testify/assert" +) + +func TestMultipleTables(t *testing.T) { + dwh := tft.NewTFBlueprintTest(t) + + dwh.DefineVerify(func(assert *assert.Assertions) { + dwh.DefaultVerify(assert) + + projectID := dwh.GetTFSetupStringOutput("project_id") + location := "US" + dataset_name := dwh.GetJSONOutput("bigquery_dataset").Get("friendly_name") + tables := dwh.GetJSONOutput("bigquery_tables") + external_tables := dwh.GetJSONOutput("bigquery_external_tables") + + ////////////////////////////////////////// + + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal(err) + } + file, err := os.Create(homeDir + "/.bigqueryrc") + if err != nil { + log.Fatal(err) + } + file.Close() + + { // Dataset test + /* + describe google_bigquery_dataset(project: "#{project_id}", name: "#{dataset_name}") do + + it { should exist } + + its('friendly_name') { should eq "#{dataset_name}" } + its('description') { should eq 'some description' } + its('location') { should eq 'US' } + its('default_table_expiration_ms') { should cmp '3600000' } + its('default_encryption_configuration.kms_key_name') { should cmp "projects/#{project_id}/locations/us/keyRings/ci-bigquery-keyring/cryptoKeys/foo" } + + end + */ + } + + { // "foo" table test + //// Maybe bq show is best... + + query := fmt.Sprintf("DESCRIBE TABLE `%s.%s`;", projectID, tablePlaceholder) + op := bq.Runf(t, "--project_id=%[1]s --headless=true --format=prettyjson query --nouse_legacy_sql %[2]s", projectID, query) + + friendlyName := op.Get("0.friendly_name").String() + friendlyNameKind := reflect.TypeOf(count).Kind() + + /* + describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:foo][:friendly_name]}") do + + it { should exist } + its('friendly_name') { should eq "#{tables[:foo][:friendly_name]}" } + its('time_partitioning.type') { should eq 'DAY' } + its('clustering') { should_not be nil } + + end + */ + } + + { // "bar" table test + /* + describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:bar][:friendly_name]}") do + + it { should exist } + its('friendly_name') { should eq "#{tables[:bar][:friendly_name]}" } + its('time_partitioning.type') { should be nil } + its('clustering') { should be nil } + + end + */ + } + + { // CSV test + /* + describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:csv_example][:friendly_name]}") do + it { should exist } + its('friendly_name') { should eq "#{external_tables[:csv_example][:friendly_name]}" } + its('time_partitioning.type') { should be nil } + its('clustering') { should be nil } + its('type') { should eq "EXTERNAL" } + its('external_data_configuration.autodetect') { should be true } + its('external_data_configuration.compression') { should eq "NONE" } + its('external_data_configuration.ignore_unknown_values') { should be true } + its('external_data_configuration.max_bad_records') { should be nil } + its('external_data_configuration.source_format') { should eq "CSV" } + its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/bigquery-external-table-test.csv"] } + + its('external_data_configuration.csv_options.quote') { should eq "\"" } + its('external_data_configuration.csv_options.allow_jagged_rows') { should be nil } + its('external_data_configuration.csv_options.allow_quoted_newlines') { should be true } + its('external_data_configuration.csv_options.encoding') { should eq "UTF-8" } + its('external_data_configuration.csv_options.field_delimiter') { should eq "," } + its('external_data_configuration.csv_options.skip_leading_rows') { should eq "1" } + end + */ + } + + { // Hive test + /* + describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:hive_example][:friendly_name]}") do + it { should exist } + its('friendly_name') { should eq "#{external_tables[:hive_example][:friendly_name]}" } + its('time_partitioning.type') { should be nil } + its('clustering') { should be nil } + its('type') { should eq "EXTERNAL" } + its('external_data_configuration.autodetect') { should be true } + its('external_data_configuration.compression') { should eq "NONE" } + its('external_data_configuration.ignore_unknown_values') { should be true } + its('external_data_configuration.max_bad_records') { should be nil } + its('external_data_configuration.source_format') { should eq "CSV" } + its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/hive_partition_example/year=2012/foo.csv","gs://ci-bq-external-data/hive_partition_example/year=2013/bar.csv"] } + end + */ + } + + { // Google Sheets test + /* + describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:google_sheets_example][:friendly_name]}") do + it { should exist } + its('type') { should eq "EXTERNAL" } + its('friendly_name') { should eq "#{external_tables[:google_sheets_example][:friendly_name]}" } + its('time_partitioning.type') { should be nil } + its('clustering') { should be nil } + its('external_data_configuration.autodetect') { should be true } + its('external_data_configuration.compression') { should eq "NONE" } + its('external_data_configuration.ignore_unknown_values') { should be true } + its('external_data_configuration.max_bad_records') { should be nil } + its('external_data_configuration.source_format') { should eq "GOOGLE_SHEETS" } + its('external_data_configuration.source_uris') { should eq ["https://docs.google.com/spreadsheets/d/15v4N2UG6bv1RmX__wru4Ei_mYMdVcM1MwRRLxFKc55s"] } + its('external_data_configuration.google_sheets_options.skip_leading_rows') { should eq "1" } + end + */ + } + + // Assert BigQuery tables & views are not empty + test_tables := func() { + + tables := []string{ + "thelook.distribution_centers", + "thelook.events", + "thelook.inventory_items", + "thelook.order_items", + "thelook.orders", + "thelook.products", + "thelook.users", + "thelook.lookerstudio_report_distribution_centers", + "thelook.lookerstudio_report_profit", + } + + query_template := "SELECT COUNT(*) AS count_rows FROM `%[1]s.%[2]s`;" + for _, table := range tables { + query := fmt.Sprintf(query_template, projectID, table) + op := bq.Runf(t, "--project_id=%[1]s --headless=true query --nouse_legacy_sql %[2]s", projectID, query) + + count := op.Get("0.count_rows").Int() + count_kind := reflect.TypeOf(count).Kind() + test_result := assert.Greater(count, int64(0)) + if test_result == true { + } else { + fmt.Printf("Some kind of error occurred while running the count query for the %[1]s table. We think it has %[2]d rows. Test failed. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[3]s \n Variable type for the count. This should be INT64: %[4]s \n ", table, count, op, count_kind) + } + } + } + test_tables() + + }) + dwh.Test() +} diff --git a/test/setup/main.tf b/test/setup/main.tf index 2e0f2833..2ac00614 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -65,12 +65,14 @@ module "project" { source = "terraform-google-modules/project-factory/google" version = "~> 18.0" - name = "ci-bigquery" - random_project_id = "true" - org_id = var.org_id - folder_id = var.folder_id - billing_account = var.billing_account - default_service_account = "keep" + name = "ci-bigquery" + random_project_id = "true" + #random_project_id_length = 8 + org_id = var.org_id + folder_id = var.folder_id + billing_account = var.billing_account + default_service_account = "keep" + deletion_policy = "DELETE" activate_apis = tolist(toset(flatten(values(local.per_module_services)))) } From 6c4931f142f37e05498dc0c5cb6a00307403680e Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Tue, 14 Oct 2025 17:24:07 +0000 Subject: [PATCH 3/7] test is passing now --- examples/multiple_tables/terraform.tfvars | 1 - .../{full => multiple_tables}/main.tf | 2 +- .../{full => multiple_tables}/outputs.tf | 0 .../sample_bq_schema.json | 0 .../terraform.tfvars | 0 .../{full => multiple_tables}/variables.tf | 2 +- .../multiple_tables/multiple_tables_test.go | 231 ++++++------------ test/setup/main.tf | 1 - 8 files changed, 83 insertions(+), 154 deletions(-) rename test/fixtures/{full => multiple_tables}/main.tf (92%) rename test/fixtures/{full => multiple_tables}/outputs.tf (100%) rename test/fixtures/{full => multiple_tables}/sample_bq_schema.json (100%) rename test/fixtures/{full => multiple_tables}/terraform.tfvars (100%) rename test/fixtures/{full => multiple_tables}/variables.tf (97%) diff --git a/examples/multiple_tables/terraform.tfvars b/examples/multiple_tables/terraform.tfvars index 96452119..aac50429 100644 --- a/examples/multiple_tables/terraform.tfvars +++ b/examples/multiple_tables/terraform.tfvars @@ -1,4 +1,3 @@ -project_id = "example-project" delete_contents_on_destroy = true default_table_expiration_ms = 3600000 dataset_labels = { diff --git a/test/fixtures/full/main.tf b/test/fixtures/multiple_tables/main.tf similarity index 92% rename from test/fixtures/full/main.tf rename to test/fixtures/multiple_tables/main.tf index 7e0339d3..1a6b233f 100644 --- a/test/fixtures/full/main.tf +++ b/test/fixtures/multiple_tables/main.tf @@ -19,5 +19,5 @@ module "example" { default_table_expiration_ms = var.default_table_expiration_ms project_id = var.project_id dataset_labels = var.dataset_labels - kms_key = jsondecode(var.kms_keys)["foo"] + kms_key = var.kms_keys.foo } diff --git a/test/fixtures/full/outputs.tf b/test/fixtures/multiple_tables/outputs.tf similarity index 100% rename from test/fixtures/full/outputs.tf rename to test/fixtures/multiple_tables/outputs.tf diff --git a/test/fixtures/full/sample_bq_schema.json b/test/fixtures/multiple_tables/sample_bq_schema.json similarity index 100% rename from test/fixtures/full/sample_bq_schema.json rename to test/fixtures/multiple_tables/sample_bq_schema.json diff --git a/test/fixtures/full/terraform.tfvars b/test/fixtures/multiple_tables/terraform.tfvars similarity index 100% rename from test/fixtures/full/terraform.tfvars rename to test/fixtures/multiple_tables/terraform.tfvars diff --git a/test/fixtures/full/variables.tf b/test/fixtures/multiple_tables/variables.tf similarity index 97% rename from test/fixtures/full/variables.tf rename to test/fixtures/multiple_tables/variables.tf index 499b7314..7adfb8bb 100644 --- a/test/fixtures/full/variables.tf +++ b/test/fixtures/multiple_tables/variables.tf @@ -24,7 +24,7 @@ variable "project_id" { variable "kms_keys" { description = "The KMS key module output" - default = null + type = map(string) } variable "dataset_labels" { diff --git a/test/integration/multiple_tables/multiple_tables_test.go b/test/integration/multiple_tables/multiple_tables_test.go index aaa62349..469da14e 100644 --- a/test/integration/multiple_tables/multiple_tables_test.go +++ b/test/integration/multiple_tables/multiple_tables_test.go @@ -16,17 +16,9 @@ package multiple_tables import ( "fmt" - "log" - "os" - "reflect" - "strings" "testing" - "time" - "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/bq" - "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" - "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/utils" "github.com/stretchr/testify/assert" ) @@ -34,169 +26,108 @@ func TestMultipleTables(t *testing.T) { dwh := tft.NewTFBlueprintTest(t) dwh.DefineVerify(func(assert *assert.Assertions) { - dwh.DefaultVerify(assert) + // Note: DefaultVerify() is unusable here because some attributes, + // such as last_modified_time, are changed outside of Terraform's knowledge. projectID := dwh.GetTFSetupStringOutput("project_id") - location := "US" - dataset_name := dwh.GetJSONOutput("bigquery_dataset").Get("friendly_name") - tables := dwh.GetJSONOutput("bigquery_tables") - external_tables := dwh.GetJSONOutput("bigquery_external_tables") - - ////////////////////////////////////////// - - homeDir, err := os.UserHomeDir() - if err != nil { - log.Fatal(err) - } - file, err := os.Create(homeDir + "/.bigqueryrc") - if err != nil { - log.Fatal(err) - } - file.Close() + tables := dwh.GetJsonOutput("bigquery_tables") + externalTables := dwh.GetJsonOutput("bigquery_external_tables") { // Dataset test - /* - describe google_bigquery_dataset(project: "#{project_id}", name: "#{dataset_name}") do - - it { should exist } - - its('friendly_name') { should eq "#{dataset_name}" } - its('description') { should eq 'some description' } - its('location') { should eq 'US' } - its('default_table_expiration_ms') { should cmp '3600000' } - its('default_encryption_configuration.kms_key_name') { should cmp "projects/#{project_id}/locations/us/keyRings/ci-bigquery-keyring/cryptoKeys/foo" } - - end - */ + dataset := dwh.GetJsonOutput("bigquery_dataset") + assert.Equal("foo", dataset.Get("friendly_name").String(), "dataset's friendly_name should be foo") + assert.Equal("some description", dataset.Get("description").String(), "dataset foo's description should be 'some description'") + assert.Equal("US", dataset.Get("location").String(), "dataset foo's location should be US") + assert.Equal(int64(3600000), dataset.Get("default_table_expiration_ms").Int(), "dataset foo's default_table_expiration_ms should be 3600000") + assert.Equal(fmt.Sprintf("projects/%s/locations/us/keyRings/ci-bigquery-keyring/cryptoKeys/foo", projectID), dataset.Get("default_encryption_configuration.0.kms_key_name").String(), "dataset foo's default_encryption_configuration.0.kms_key_name") } { // "foo" table test - //// Maybe bq show is best... - - query := fmt.Sprintf("DESCRIBE TABLE `%s.%s`;", projectID, tablePlaceholder) - op := bq.Runf(t, "--project_id=%[1]s --headless=true --format=prettyjson query --nouse_legacy_sql %[2]s", projectID, query) + fooTable := tables.Get("foo") + assert.Equal("foo", fooTable.Get("friendly_name").String(), "table's friendly_name should be foo") + assert.Equal("DAY", fooTable.Get("time_partitioning.0.type").String(), "foo table's time_partitioning.type should be DAY") - friendlyName := op.Get("0.friendly_name").String() - friendlyNameKind := reflect.TypeOf(count).Kind() - - /* - describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:foo][:friendly_name]}") do - - it { should exist } - its('friendly_name') { should eq "#{tables[:foo][:friendly_name]}" } - its('time_partitioning.type') { should eq 'DAY' } - its('clustering') { should_not be nil } - - end - */ + assert.Greater(len(fooTable.Get("clustering").Array()), 0, "foo table's clustering should be nonempty") } { // "bar" table test - /* - describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{tables[:bar][:friendly_name]}") do - - it { should exist } - its('friendly_name') { should eq "#{tables[:bar][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - - end - */ + barTable := tables.Get("bar") + assert.True(barTable.Exists(), "bar table should exist in terraform outputs") + assert.Equal("bar", barTable.Get("friendly_name").String(), "table's friendly_name should be bar") + assert.False(barTable.Get("time_partitioning.0.type").Exists(), "bar table's time_partitioning.type should be null") + assert.Len(barTable.Get("clustering").Array(), 0, "bar table's clustering should be empty") } { // CSV test - /* - describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:csv_example][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{external_tables[:csv_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('type') { should eq "EXTERNAL" } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "CSV" } - its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/bigquery-external-table-test.csv"] } - - its('external_data_configuration.csv_options.quote') { should eq "\"" } - its('external_data_configuration.csv_options.allow_jagged_rows') { should be nil } - its('external_data_configuration.csv_options.allow_quoted_newlines') { should be true } - its('external_data_configuration.csv_options.encoding') { should eq "UTF-8" } - its('external_data_configuration.csv_options.field_delimiter') { should eq "," } - its('external_data_configuration.csv_options.skip_leading_rows') { should eq "1" } - end - */ + csvTable := externalTables.Get("csv_example") + assert.True(csvTable.Exists(), "csv_example table should exist in terraform outputs") + assert.Equal("csv_example", csvTable.Get("friendly_name").String(), "table's friendly_name should be csv_example") + assert.False(csvTable.Get("time_partitioning.0.type").Exists(), "csv_example table's time_partitioning.type should be null") + assert.Len(csvTable.Get("clustering").Array(), 0, "csv_example table's clustering should be empty") + assert.Equal("EXTERNAL", csvTable.Get("type").String(), "csv_example table's type should be EXTERNAL") + + csvDataConfig := csvTable.Get("external_data_configuration.0") + assert.True(csvDataConfig.Exists(), "csv_example table should contain external_data_configuration") + assert.True(csvDataConfig.Get("autodetect").Bool(), "csv_example.external_data_configuration.autodetect should be true") + assert.Equal("NONE", csvDataConfig.Get("compression").String(), "csv_example.external_data_configuration.compression should be NONE") + assert.True(csvDataConfig.Get("ignore_unknown_values").Bool(), "csv_example.external_data_configuration.ignore_unknown_values should be true") + assert.Equal(int64(0), csvDataConfig.Get("max_bad_records").Int(), "csv_example.external_data_configuration.max_bad_records should be 0") + assert.Equal("CSV", csvDataConfig.Get("source_format").String(), "csv_example.external_data_configuration.source_format should be CSV") + assert.Len(csvDataConfig.Get("source_uris").Array(), 1, "csv_example.external_data_configuration.source_uris should have 1 element") + assert.Equal("gs://ci-bq-external-data/bigquery-external-table-test.csv", csvDataConfig.Get("source_uris.0").String(), "csv_example.external_data_configuration.source_uris[0] should have the expected URI") + + csvOptions := csvDataConfig.Get("csv_options.0") + assert.True(csvOptions.Exists(), "csv_example table should contain external_data_configuration.csv_options") + assert.Equal(`"`, csvOptions.Get("quote").String(), `csv_example.external_data_configuration.csv_options should be " (a quote character)`) + assert.False(csvOptions.Get("allow_jagged_rows").Bool(), "csv_example.external_data_configuration.csv_options.allow_jagged_rows should be false") + assert.Equal(true, csvOptions.Get("allow_quoted_newlines").Bool(), "csv_example.external_data_configuration.csv_options.allow_quoted_newlines should be true") + assert.Equal("UTF-8", csvOptions.Get("encoding").String(), "csv_example.external_data_configuration.csv_options.encoding should be UTF-8") + assert.Equal(",", csvOptions.Get("field_delimiter").String(), "csv_example.external_data_configuration.csv_options.field_delimiter should be ,") + assert.Equal(int64(1), csvOptions.Get("skip_leading_rows").Int(), "csv_example.external_data_configuration.csv_options.skip_leading_rows should be 1") } { // Hive test - /* - describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:hive_example][:friendly_name]}") do - it { should exist } - its('friendly_name') { should eq "#{external_tables[:hive_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('type') { should eq "EXTERNAL" } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "CSV" } - its('external_data_configuration.source_uris') { should eq ["gs://ci-bq-external-data/hive_partition_example/year=2012/foo.csv","gs://ci-bq-external-data/hive_partition_example/year=2013/bar.csv"] } - end - */ + hiveTable := externalTables.Get("hive_example") + assert.True(hiveTable.Exists(), "hive_example table should exist in terraform outputs") + assert.Equal("hive_example", hiveTable.Get("friendly_name").String(), "table's friendly_name should be hive_example") + assert.False(hiveTable.Get("time_partitioning.0.type").Exists(), "hive_example table's time_partitioning.type should be null") + assert.Len(hiveTable.Get("clustering").Array(), 0, "hive_example table's clustering should be empty") + assert.Equal("EXTERNAL", hiveTable.Get("type").String(), "hive_example table's type should be EXTERNAL") + + hiveDataConfig := hiveTable.Get("external_data_configuration.0") + assert.True(hiveDataConfig.Exists(), "hive_example table should contain external_data_configuration") + assert.True(hiveDataConfig.Get("autodetect").Bool(), "hive_example.external_data_configuration.autodetect should be true") + assert.Equal("NONE", hiveDataConfig.Get("compression").String(), "hive_example.external_data_configuration.compression should be NONE") + assert.True(hiveDataConfig.Get("ignore_unknown_values").Bool(), "hive_example.external_data_configuration.ignore_unknown_values should be true") + assert.Equal(int64(0), hiveDataConfig.Get("max_bad_records").Int(), "hive_example.external_data_configuration.max_bad_records should be 0") + assert.Equal("CSV", hiveDataConfig.Get("source_format").String(), "hive_example.external_data_configuration.source_format should be CSV") + + assert.Len(hiveDataConfig.Get("source_uris").Array(), 2, "hive_example.external_data_configuration.source_uris should have 2 elements") + assert.Equal("gs://ci-bq-external-data/hive_partition_example/year=2012/foo.csv", hiveDataConfig.Get("source_uris.0").String(), "hive_example.external_data_configuration.source_uris[0] should have the expected URI") + assert.Equal("gs://ci-bq-external-data/hive_partition_example/year=2013/bar.csv", hiveDataConfig.Get("source_uris.1").String(), "hive_example.external_data_configuration.source_uris[1] should have the expected URI") } { // Google Sheets test - /* - describe google_bigquery_table(project: "#{project_id}", dataset: "#{dataset_name}", name: "#{external_tables[:google_sheets_example][:friendly_name]}") do - it { should exist } - its('type') { should eq "EXTERNAL" } - its('friendly_name') { should eq "#{external_tables[:google_sheets_example][:friendly_name]}" } - its('time_partitioning.type') { should be nil } - its('clustering') { should be nil } - its('external_data_configuration.autodetect') { should be true } - its('external_data_configuration.compression') { should eq "NONE" } - its('external_data_configuration.ignore_unknown_values') { should be true } - its('external_data_configuration.max_bad_records') { should be nil } - its('external_data_configuration.source_format') { should eq "GOOGLE_SHEETS" } - its('external_data_configuration.source_uris') { should eq ["https://docs.google.com/spreadsheets/d/15v4N2UG6bv1RmX__wru4Ei_mYMdVcM1MwRRLxFKc55s"] } - its('external_data_configuration.google_sheets_options.skip_leading_rows') { should eq "1" } - end - */ - } - - // Assert BigQuery tables & views are not empty - test_tables := func() { - - tables := []string{ - "thelook.distribution_centers", - "thelook.events", - "thelook.inventory_items", - "thelook.order_items", - "thelook.orders", - "thelook.products", - "thelook.users", - "thelook.lookerstudio_report_distribution_centers", - "thelook.lookerstudio_report_profit", - } - - query_template := "SELECT COUNT(*) AS count_rows FROM `%[1]s.%[2]s`;" - for _, table := range tables { - query := fmt.Sprintf(query_template, projectID, table) - op := bq.Runf(t, "--project_id=%[1]s --headless=true query --nouse_legacy_sql %[2]s", projectID, query) - - count := op.Get("0.count_rows").Int() - count_kind := reflect.TypeOf(count).Kind() - test_result := assert.Greater(count, int64(0)) - if test_result == true { - } else { - fmt.Printf("Some kind of error occurred while running the count query for the %[1]s table. We think it has %[2]d rows. Test failed. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[3]s \n Variable type for the count. This should be INT64: %[4]s \n ", table, count, op, count_kind) - } - } + sheetsTable := externalTables.Get("google_sheets_example") + assert.True(sheetsTable.Exists(), "google_sheets_example table should exist in terraform outputs") + assert.Equal("google_sheets_example", sheetsTable.Get("friendly_name").String(), "table's friendly_name should be google_sheets_example") + assert.False(sheetsTable.Get("time_partitioning.0.type").Exists(), "google_sheets_example table's time_partitioning.type should be null") + assert.Len(sheetsTable.Get("clustering").Array(), 0, "google_sheets_example table's clustering should be empty") + assert.Equal("EXTERNAL", sheetsTable.Get("type").String(), "google_sheets_example table's type should be EXTERNAL") + + sheetsDataConfig := sheetsTable.Get("external_data_configuration.0") + assert.True(sheetsDataConfig.Exists(), "google_sheets_example table should contain external_data_configuration") + assert.True(sheetsDataConfig.Get("autodetect").Bool(), "google_sheets_example.external_data_configuration.autodetect should be true") + assert.Equal("NONE", sheetsDataConfig.Get("compression").String(), "google_sheets_example.external_data_configuration.compression should be NONE") + assert.True(sheetsDataConfig.Get("ignore_unknown_values").Bool(), "google_sheets_example.external_data_configuration.ignore_unknown_values should be true") + assert.Equal(int64(0), sheetsDataConfig.Get("max_bad_records").Int(), "google_sheets_example.external_data_configuration.max_bad_records should be 0") + assert.Equal("GOOGLE_SHEETS", sheetsDataConfig.Get("source_format").String(), "google_sheets_example.external_data_configuration.source_format should be CSV") + + assert.Len(sheetsDataConfig.Get("source_uris").Array(), 1, "google_sheets_example.external_data_configuration.source_uris should have 1 element") + assert.Equal("https://docs.google.com/spreadsheets/d/15v4N2UG6bv1RmX__wru4Ei_mYMdVcM1MwRRLxFKc55s", sheetsDataConfig.Get("source_uris.0").String(), "google_sheets_example.external_data_configuration.source_uris[0] should have the expected URI") + + assert.Equal(int64(1), sheetsDataConfig.Get("google_sheets_options.0.skip_leading_rows").Int(), "google_sheets_example.external_data_configuration.google_sheets_options.0.skip_leading_rows should be 1") } - test_tables() - }) dwh.Test() } diff --git a/test/setup/main.tf b/test/setup/main.tf index 2ac00614..fcf76bde 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -67,7 +67,6 @@ module "project" { name = "ci-bigquery" random_project_id = "true" - #random_project_id_length = 8 org_id = var.org_id folder_id = var.folder_id billing_account = var.billing_account From af88217685bd132691efc08d3f4ee74ab3be2ab5 Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Tue, 14 Oct 2025 17:28:12 +0000 Subject: [PATCH 4/7] remove waitFor --- build/int.cloudbuild.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index 2869fdb4..e9780177 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -28,7 +28,6 @@ steps: name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'cft test run TestMultipleTables --verbose'] - id: create-dwh - waitFor: prepare name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'cft test run TestDataWarehouse --stage init --verbose'] - id: apply-dwh From b7f024480201878182ebd188c2fd0891bc63594d Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Tue, 14 Oct 2025 17:29:18 +0000 Subject: [PATCH 5/7] fix lint --- test/setup/main.tf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/setup/main.tf b/test/setup/main.tf index fcf76bde..a05fb7d6 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -65,13 +65,13 @@ module "project" { source = "terraform-google-modules/project-factory/google" version = "~> 18.0" - name = "ci-bigquery" - random_project_id = "true" - org_id = var.org_id - folder_id = var.folder_id - billing_account = var.billing_account - default_service_account = "keep" - deletion_policy = "DELETE" + name = "ci-bigquery" + random_project_id = "true" + org_id = var.org_id + folder_id = var.folder_id + billing_account = var.billing_account + default_service_account = "keep" + deletion_policy = "DELETE" activate_apis = tolist(toset(flatten(values(local.per_module_services)))) } From 3134306e9b427fb7dccf944d87096707453ea329 Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Tue, 14 Oct 2025 17:35:15 +0000 Subject: [PATCH 6/7] remove some unnecessary diffs --- examples/multiple_tables/terraform.tfvars | 1 + .../data_warehouse/data_warehouse_test.go | 43 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/examples/multiple_tables/terraform.tfvars b/examples/multiple_tables/terraform.tfvars index aac50429..96452119 100644 --- a/examples/multiple_tables/terraform.tfvars +++ b/examples/multiple_tables/terraform.tfvars @@ -1,3 +1,4 @@ +project_id = "example-project" delete_contents_on_destroy = true default_table_expiration_ms = 3600000 dataset_labels = { diff --git a/test/integration/data_warehouse/data_warehouse_test.go b/test/integration/data_warehouse/data_warehouse_test.go index a3864cfd..b92be595 100644 --- a/test/integration/data_warehouse/data_warehouse_test.go +++ b/test/integration/data_warehouse/data_warehouse_test.go @@ -66,28 +66,28 @@ func TestDataWarehouse(t *testing.T) { utils.Poll(t, verifyWorkflows, 8, 30*time.Second) homeDir, err := os.UserHomeDir() - if err != nil { - log.Fatal(err) - } - file, err := os.Create(homeDir + "/.bigqueryrc") - if err != nil { - log.Fatal(err) - } - file.Close() + if err != nil { + log.Fatal(err) + } + file, err := os.Create(homeDir + "/.bigqueryrc") + if err != nil { + log.Fatal(err) + } + file.Close() // Assert BigQuery tables & views are not empty - test_tables := func() { + test_tables := func (){ tables := []string{ - "thelook.distribution_centers", - "thelook.events", - "thelook.inventory_items", - "thelook.order_items", - "thelook.orders", - "thelook.products", - "thelook.users", - "thelook.lookerstudio_report_distribution_centers", - "thelook.lookerstudio_report_profit", + "thelook.distribution_centers", + "thelook.events", + "thelook.inventory_items", + "thelook.order_items", + "thelook.orders", + "thelook.products", + "thelook.users", + "thelook.lookerstudio_report_distribution_centers", + "thelook.lookerstudio_report_profit", } query_template := "SELECT COUNT(*) AS count_rows FROM `%[1]s.%[2]s`;" @@ -108,6 +108,7 @@ func TestDataWarehouse(t *testing.T) { // Assert BigQuery connection to Vertex GenAI was successfully created and works as expected test_llms := func() { + llm_query_template := "SELECT COUNT(*) AS count_rows FROM ML.GENERATE_TEXT(MODEL `%[1]s.thelook.text_generate_model`, (with clusters AS(SELECT CONCAT('cluster', CAST(centroid_id as STRING)) as centroid, avg_spend as average_spend, count_orders as count_of_orders, days_since_order FROM (SELECT centroid_id, feature, ROUND(numerical_value, 2) as value FROM ML.CENTROIDS(MODEL `%[1]s.thelook.customer_segment_clustering`)) PIVOT (SUM(value) FOR feature IN ('avg_spend', 'count_orders', 'days_since_order')) ORDER BY centroid_id) SELECT 'Pretend you are a creative strategist, given the following clusters come up with creative brand persona and title labels for each of these clusters, and explain step by step; what would be the next marketing step for these clusters' || ' ' || clusters.centroid || ', Average Spend $' || clusters.average_spend || ', Count of orders per person ' || clusters.count_of_orders || ', Days since last order ' || clusters.days_since_order AS prompt FROM clusters), STRUCT(800 AS max_output_tokens, 0.8 AS temperature, 40 AS top_k, 0.8 AS top_p, TRUE AS flatten_json_output));" query := fmt.Sprintf(llm_query_template, projectID) llm_op := bq.Runf(t, "--project_id=%[1]s --headless=true query --nouse_legacy_sql %[2]s", projectID, query) @@ -116,9 +117,9 @@ func TestDataWarehouse(t *testing.T) { count_llm_kind := reflect.TypeOf(llm_count).Kind() llm_test_result := assert.Greater(llm_count, int64(0)) if llm_test_result == true { - } else { - fmt.Printf("Some kind of error occurred while running the llm_count query. We think it has %[1]d rows. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[2]s \n Variable type for the count. This should be INT64: %[3]s \n ", llm_count, llm_op, count_llm_kind) - } + } else { + fmt.Printf("Some kind of error occurred while running the llm_count query. We think it has %[1]d rows. Here's some additional details: \n Query results. If this number is greater than 0, then there is probably an issue in the comparison: %[2]s \n Variable type for the count. This should be INT64: %[3]s \n ", llm_count, llm_op, count_llm_kind) + } } test_llms() }) From 3e87200d93febe7146e3429c75e261f5d280a236 Mon Sep 17 00:00:00 2001 From: Martijn van Schaardenburg Date: Fri, 17 Oct 2025 18:31:28 +0000 Subject: [PATCH 7/7] add DefaultVerify() even though it is currently broken --- test/integration/multiple_tables/multiple_tables_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/multiple_tables/multiple_tables_test.go b/test/integration/multiple_tables/multiple_tables_test.go index 469da14e..0e209f2a 100644 --- a/test/integration/multiple_tables/multiple_tables_test.go +++ b/test/integration/multiple_tables/multiple_tables_test.go @@ -26,8 +26,8 @@ func TestMultipleTables(t *testing.T) { dwh := tft.NewTFBlueprintTest(t) dwh.DefineVerify(func(assert *assert.Assertions) { - // Note: DefaultVerify() is unusable here because some attributes, - // such as last_modified_time, are changed outside of Terraform's knowledge. + // This call is failing with "plan after apply should have no diffs", needs investigation. + dwh.DefaultVerify(assert) projectID := dwh.GetTFSetupStringOutput("project_id") tables := dwh.GetJsonOutput("bigquery_tables")