From dec7cd9e199ac8658f5c939f811686ba9f5e2e21 Mon Sep 17 00:00:00 2001
From: Artur Sawicki <artur.sawicki@snowflake.com>
Date: Fri, 26 Jan 2024 12:46:20 +0100
Subject: [PATCH] fix: Fix some bugs (#2421)

Fix a few small bugs

All of them have appropriate tests showing the error before and correct
behavior after.

#### Fix blocked roles issue in oauth integration (#2358)
`BLOCKED_ROLES_LIST ` was cast to wrong type which caused panic
(https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/pkg/resources/oauth_integration.go#L313).

#### Fix database replication setup in resource (#2369)
No old config for blocked roles was causing empty list access
(https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/e3d086eddc05e0d4963234f82e09e174a018bb08/pkg/resources/database.go#L271).
Some other errors were discovered, so implementation was slightly
improved.

#### Do not read query for dynamic table (#2329)
Cutting query from returned DDL was too greedy
(https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/e3d086eddc05e0d4963234f82e09e174a018bb08/pkg/resources/dynamic_table.go#L204).
It is not that simple to read the right part. We may skip reading it,
though, but it will make the import not fully functional. At the end,
the matching was improved to handle more cases and appropriate test
cases were added. The full explanation in
https://github.com/Snowflake-Labs/terraform-provider-snowflake/pull/2421/files#diff-33718834696cbceb48b07f4a6aa4f739d1aa9052e190996a309f650c2e5a9edcR258.

#### Fix incorrectly merged streamlits
Formatting and `createStage` usage.

Fix #2358
Fix #2369
Fix #2329
---
 pkg/resources/database.go                     | 27 ++++--
 pkg/resources/database_acceptance_test.go     | 55 +++++++++++-
 pkg/resources/dynamic_table.go                | 45 ++++++++--
 .../dynamic_table_acceptance_test.go          | 83 +++++++++++++++++++
 pkg/resources/oauth_integration.go            |  2 +-
 .../oauth_integration_acceptance_test.go      | 17 +++-
 .../TestAcc_DynamicTable_issue2329/1/test.tf  | 27 ++++++
 .../1/variables.tf                            | 27 ++++++
 pkg/sdk/client.go                             |  2 +-
 pkg/sdk/poc/main.go                           |  2 +-
 .../testint/streamlits_integration_test.go    | 12 +--
 11 files changed, 267 insertions(+), 32 deletions(-)
 create mode 100644 pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/test.tf
 create mode 100644 pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/variables.tf

diff --git a/pkg/resources/database.go b/pkg/resources/database.go
index 275cb3b2fa..d30b7ec0c5 100644
--- a/pkg/resources/database.go
+++ b/pkg/resources/database.go
@@ -263,16 +263,25 @@ func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
 	// If replication configuration changes, need to update accounts that have permission to replicate database
 	if d.HasChange("replication_configuration") {
 		oldConfig, newConfig := d.GetChange("replication_configuration")
-		newAccounts := newConfig.([]interface{})[0].(map[string]interface{})["accounts"].([]interface{})
-		newAccountIDs := make([]sdk.AccountIdentifier, len(newAccounts))
-		for i, account := range newAccounts {
-			newAccountIDs[i] = sdk.NewAccountIdentifierFromAccountLocator(account.(string))
+
+		newAccountIDs := make([]sdk.AccountIdentifier, 0)
+		ignoreEditionCheck := false
+		if len(newConfig.([]interface{})) != 0 {
+			newAccounts := newConfig.([]interface{})[0].(map[string]interface{})["accounts"].([]interface{})
+			for _, account := range newAccounts {
+				newAccountIDs = append(newAccountIDs, sdk.NewAccountIdentifierFromAccountLocator(account.(string)))
+			}
+			ignoreEditionCheck = newConfig.([]interface{})[0].(map[string]interface{})["ignore_edition_check"].(bool)
 		}
-		oldAccounts := oldConfig.([]interface{})[0].(map[string]interface{})["accounts"].([]interface{})
-		oldAccountIDs := make([]sdk.AccountIdentifier, len(oldAccounts))
-		for i, account := range oldAccounts {
-			oldAccountIDs[i] = sdk.NewAccountIdentifierFromAccountLocator(account.(string))
+
+		oldAccountIDs := make([]sdk.AccountIdentifier, 0)
+		if len(oldConfig.([]interface{})) != 0 {
+			oldAccounts := oldConfig.([]interface{})[0].(map[string]interface{})["accounts"].([]interface{})
+			for _, account := range oldAccounts {
+				oldAccountIDs = append(oldAccountIDs, sdk.NewAccountIdentifierFromAccountLocator(account.(string)))
+			}
 		}
+
 		accountsToRemove := make([]sdk.AccountIdentifier, 0)
 		accountsToAdd := make([]sdk.AccountIdentifier, 0)
 		// Find accounts to remove
@@ -294,7 +303,7 @@ func UpdateDatabase(d *schema.ResourceData, meta interface{}) error {
 					ToAccounts: accountsToAdd,
 				},
 			}
-			if ignoreEditionCheck := d.Get("ignore_edition_check").(bool); ignoreEditionCheck {
+			if ignoreEditionCheck {
 				opts.EnableReplication.IgnoreEditionCheck = sdk.Bool(ignoreEditionCheck)
 			}
 			err := client.Databases.AlterReplication(ctx, id, opts)
diff --git a/pkg/resources/database_acceptance_test.go b/pkg/resources/database_acceptance_test.go
index 21b20c506f..a5e7f22b29 100644
--- a/pkg/resources/database_acceptance_test.go
+++ b/pkg/resources/database_acceptance_test.go
@@ -49,6 +49,8 @@ func TestAcc_Database(t *testing.T) {
 	prefix := "tst-terraform" + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
 	prefix2 := "tst-terraform" + strings.ToUpper(acctest.RandStringFromCharSet(10, acctest.CharSetAlpha))
 
+	secondaryAccountName := getSecondaryAccount(t)
+
 	resource.ParallelTest(t, resource.TestCase{
 		Providers:    acc.TestAccProviders(),
 		PreCheck:     func() { acc.TestAccPreCheck(t) },
@@ -80,11 +82,25 @@ func TestAcc_Database(t *testing.T) {
 					resource.TestCheckResourceAttr("snowflake_database.db", "data_retention_time_in_days", "3"),
 				),
 			},
+			// ADD REPLICATION
+			// proves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2369 error
+			{
+				Config: dbConfigWithReplication(prefix2, secondaryAccountName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_database.db", "name", prefix2),
+					resource.TestCheckResourceAttr("snowflake_database.db", "comment", "test comment 2"),
+					resource.TestCheckResourceAttr("snowflake_database.db", "data_retention_time_in_days", "3"),
+					resource.TestCheckResourceAttr("snowflake_database.db", "replication_configuration.#", "1"),
+					resource.TestCheckResourceAttr("snowflake_database.db", "replication_configuration.0.accounts.#", "1"),
+					resource.TestCheckResourceAttr("snowflake_database.db", "replication_configuration.0.accounts.0", secondaryAccountName),
+				),
+			},
 			// IMPORT
 			{
-				ResourceName:      "snowflake_database.db",
-				ImportState:       true,
-				ImportStateVerify: true,
+				ResourceName:            "snowflake_database.db",
+				ImportState:             true,
+				ImportStateVerify:       true,
+				ImportStateVerifyIgnore: []string{"replication_configuration"},
 			},
 		},
 	})
@@ -155,6 +171,22 @@ resource "snowflake_database" "db" {
 	return fmt.Sprintf(s, prefix)
 }
 
+func dbConfigWithReplication(prefix string, secondaryAccountName string) string {
+	s := `
+resource "snowflake_database" "db" {
+	name = "%s"
+	comment = "test comment 2"
+	data_retention_time_in_days = 3
+	replication_configuration {
+		accounts = [
+			"%s"
+		]
+	}
+}
+`
+	return fmt.Sprintf(s, prefix, secondaryAccountName)
+}
+
 func dropDatabaseOutsideTerraform(t *testing.T, id string) {
 	t.Helper()
 
@@ -166,6 +198,23 @@ func dropDatabaseOutsideTerraform(t *testing.T, id string) {
 	require.NoError(t, err)
 }
 
+func getSecondaryAccount(t *testing.T) string {
+	t.Helper()
+
+	secondaryConfig, err := sdk.ProfileConfig("secondary_test_account")
+	require.NoError(t, err)
+
+	secondaryClient, err := sdk.NewClient(secondaryConfig)
+	require.NoError(t, err)
+
+	ctx := context.Background()
+
+	account, err := secondaryClient.ContextFunctions.CurrentAccount(ctx)
+	require.NoError(t, err)
+
+	return account
+}
+
 func testAccCheckDatabaseExistence(t *testing.T, id string, shouldExist bool) func(state *terraform.State) error {
 	t.Helper()
 	return func(state *terraform.State) error {
diff --git a/pkg/resources/dynamic_table.go b/pkg/resources/dynamic_table.go
index 90cbdd1c22..49446f14f4 100644
--- a/pkg/resources/dynamic_table.go
+++ b/pkg/resources/dynamic_table.go
@@ -3,6 +3,7 @@ package resources
 import (
 	"context"
 	"database/sql"
+	"errors"
 	"log"
 	"strings"
 
@@ -190,8 +191,7 @@ func ReadDynamicTable(d *schema.ResourceData, meta interface{}) error {
 			return err
 		}
 	}
-	text := dynamicTable.Text
-	if strings.Contains(text, "OR REPLACE") {
+	if strings.Contains(dynamicTable.Text, "OR REPLACE") {
 		if err := d.Set("or_replace", true); err != nil {
 			return err
 		}
@@ -200,11 +200,6 @@ func ReadDynamicTable(d *schema.ResourceData, meta interface{}) error {
 			return err
 		}
 	}
-	// trim up to " ..AS" and remove whitespace
-	query := strings.TrimSpace(text[strings.Index(text, "AS")+3:])
-	if err := d.Set("query", query); err != nil {
-		return err
-	}
 	if err := d.Set("cluster_by", dynamicTable.ClusterBy); err != nil {
 		return err
 	}
@@ -247,9 +242,45 @@ func ReadDynamicTable(d *schema.ResourceData, meta interface{}) error {
 	if err := d.Set("data_timestamp", dynamicTable.DataTimestamp.Format("2006-01-02T16:04:05.000 -0700")); err != nil {
 		return err
 	}
+
+	query, err := getQueryFromDDL(dynamicTable.Text)
+	if err != nil {
+		return err
+	}
+	if err := d.Set("query", query); err != nil {
+		return err
+	}
+
 	return nil
 }
 
+/*
+ * Previous implementation tried to match query part from the whole dynamic table DDL statement by just using `AS`.
+ * It was failing for table names containing `AS` (like `REASON`). It was also failing for other parts containing `AS`.
+ * We cannot simply match by ` AS ` because this can still be part of COMMENT or SELECT query itself.
+ * We have considered not setting the query at all but it was not ideal because of:
+ * - possible external changes to dynamic table (drop and recreate externally with different query);
+ * - import not 100% correct.
+ * We did not want to complicate the implementation too much by introducing parsers.
+ * One more thing worth mentioning is the whitespace that can be introduced by the user that is still returned by SHOW.
+ * For now, we just normalize the DDL before extraction of query.
+ *
+ * The outcome implementation matches by ` AS SELECT ` and checks the number of matches.
+ * If more matches are found, the error is returned to inform user about possible cause of error.
+ *
+ * Refer to issue https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2329.
+ */
+func getQueryFromDDL(text string) (string, error) {
+	normalizedDDL := normalizeQuery(text)
+	matchSubstring := " AS SELECT "
+	matches := strings.Count(strings.ToUpper(normalizedDDL), matchSubstring)
+	if matches != 1 {
+		return "", errors.New("too many matches found. There is no way of getting ONLY the 'query' used to create the dynamic table from Snowflake. We try to get it from the whole creation statement but there may be cases where it fails. Please submit the issue on Github (refer to #2329)")
+	}
+	idx := strings.Index(strings.ToUpper(normalizedDDL), " AS SELECT ")
+	return strings.TrimSpace(normalizedDDL[idx+4:]), nil
+}
+
 func parseTargetLag(v interface{}) sdk.TargetLag {
 	var result sdk.TargetLag
 	tl := v.([]interface{})[0].(map[string]interface{})
diff --git a/pkg/resources/dynamic_table_acceptance_test.go b/pkg/resources/dynamic_table_acceptance_test.go
index 6a59b1c37d..e638b9a412 100644
--- a/pkg/resources/dynamic_table_acceptance_test.go
+++ b/pkg/resources/dynamic_table_acceptance_test.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"database/sql"
 	"fmt"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -284,6 +285,88 @@ func TestAcc_DynamicTable_issue2276(t *testing.T) {
 	})
 }
 
+// TestAcc_DynamicTable_issue2329 proves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2329 issue.
+func TestAcc_DynamicTable_issue2329(t *testing.T) {
+	dynamicTableName := strings.ToUpper(acctest.RandStringFromCharSet(4, acctest.CharSetAlpha) + "AS" + acctest.RandStringFromCharSet(4, acctest.CharSetAlpha))
+	tableName := dynamicTableName + "_table"
+	query := fmt.Sprintf(`select "id" from "%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, tableName)
+	m := func() map[string]config.Variable {
+		return map[string]config.Variable{
+			"name":      config.StringVariable(dynamicTableName),
+			"database":  config.StringVariable(acc.TestDatabaseName),
+			"schema":    config.StringVariable(acc.TestSchemaName),
+			"warehouse": config.StringVariable(acc.TestWarehouseName),
+			// spaces added on purpose
+			"query":      config.StringVariable("  " + query),
+			"comment":    config.StringVariable("Comment with AS on purpose"),
+			"table_name": config.StringVariable(tableName),
+		}
+	}
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+		PreCheck:                 func() { acc.TestAccPreCheck(t) },
+		TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+			tfversion.RequireAbove(tfversion.Version1_5_0),
+		},
+		CheckDestroy: testAccCheckDynamicTableDestroy,
+		Steps: []resource.TestStep{
+			{
+				ConfigDirectory: config.TestStepDirectory(),
+				ConfigVariables: m(),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_dynamic_table.dt", "name", dynamicTableName),
+					resource.TestCheckResourceAttr("snowflake_dynamic_table.dt", "query", query),
+				),
+			},
+			// No changes are expected
+			{
+				ConfigDirectory: acc.ConfigurationSameAsStepN(1),
+				ConfigVariables: m(),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_dynamic_table.dt", "name", dynamicTableName),
+					resource.TestCheckResourceAttr("snowflake_dynamic_table.dt", "query", query),
+				),
+			},
+		},
+	})
+}
+
+// TestAcc_DynamicTable_issue2329_with_matching_comment proves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2329 issue.
+func TestAcc_DynamicTable_issue2329_with_matching_comment(t *testing.T) {
+	dynamicTableName := strings.ToUpper(acctest.RandStringFromCharSet(4, acctest.CharSetAlpha) + "AS" + acctest.RandStringFromCharSet(4, acctest.CharSetAlpha))
+	tableName := dynamicTableName + "_table"
+	query := fmt.Sprintf(`select "id" from "%v"."%v"."%v"`, acc.TestDatabaseName, acc.TestSchemaName, tableName)
+	m := func() map[string]config.Variable {
+		return map[string]config.Variable{
+			"name":       config.StringVariable(dynamicTableName),
+			"database":   config.StringVariable(acc.TestDatabaseName),
+			"schema":     config.StringVariable(acc.TestSchemaName),
+			"warehouse":  config.StringVariable(acc.TestWarehouseName),
+			"query":      config.StringVariable(query),
+			"comment":    config.StringVariable("Comment with AS SELECT on purpose"),
+			"table_name": config.StringVariable(tableName),
+		}
+	}
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories,
+		PreCheck:                 func() { acc.TestAccPreCheck(t) },
+		TerraformVersionChecks: []tfversion.TerraformVersionCheck{
+			tfversion.RequireAbove(tfversion.Version1_5_0),
+		},
+		CheckDestroy: testAccCheckDynamicTableDestroy,
+		Steps: []resource.TestStep{
+			// If we match more than one time (in this case in comment) we raise an explanation error.
+			{
+				ConfigDirectory: acc.ConfigurationDirectory("TestAcc_DynamicTable_issue2329/1"),
+				ConfigVariables: m(),
+				ExpectError:     regexp.MustCompile(`too many matches found. There is no way of getting ONLY the 'query' used to create the dynamic table from Snowflake. We try to get it from the whole creation statement but there may be cases where it fails. Please submit the issue on Github \(refer to #2329\)`),
+			},
+		},
+	})
+}
+
 func testAccCheckDynamicTableDestroy(s *terraform.State) error {
 	db := acc.TestAccProvider.Meta().(*sql.DB)
 	client := sdk.NewClientFromDB(db)
diff --git a/pkg/resources/oauth_integration.go b/pkg/resources/oauth_integration.go
index 0202d63a16..f067a830bc 100644
--- a/pkg/resources/oauth_integration.go
+++ b/pkg/resources/oauth_integration.go
@@ -310,7 +310,7 @@ func UpdateOAuthIntegration(d *schema.ResourceData, meta interface{}) error {
 
 	if d.HasChange("blocked_roles_list") {
 		runSetStatement = true
-		stmt.SetStringList(`BLOCKED_ROLES_LIST`, expandStringList(d.Get("blocked_roles_list").([]interface{})))
+		stmt.SetStringList(`BLOCKED_ROLES_LIST`, expandStringList(d.Get("blocked_roles_list").(*schema.Set).List()))
 	}
 
 	if d.HasChange("enabled") {
diff --git a/pkg/resources/oauth_integration_acceptance_test.go b/pkg/resources/oauth_integration_acceptance_test.go
index 9b8bbbc5dd..f2fa188bf7 100644
--- a/pkg/resources/oauth_integration_acceptance_test.go
+++ b/pkg/resources/oauth_integration_acceptance_test.go
@@ -21,7 +21,7 @@ func TestAcc_OAuthIntegration(t *testing.T) {
 		CheckDestroy: nil,
 		Steps: []resource.TestStep{
 			{
-				Config: oauthIntegrationConfig(name, oauthClient, clientType),
+				Config: oauthIntegrationConfig(name, oauthClient, clientType, "SYSADMIN"),
 				Check: resource.ComposeTestCheckFunc(
 					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "name", name),
 					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "oauth_client", oauthClient),
@@ -32,6 +32,15 @@ func TestAcc_OAuthIntegration(t *testing.T) {
 					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "blocked_roles_list.0", "SYSADMIN"),
 				),
 			},
+			{
+				// role change proves https://github.com/Snowflake-Labs/terraform-provider-snowflake/issues/2358 issue
+				Config: oauthIntegrationConfig(name, oauthClient, clientType, "USERADMIN"),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "name", name),
+					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "blocked_roles_list.#", "1"),
+					resource.TestCheckResourceAttr("snowflake_oauth_integration.test", "blocked_roles_list.0", "USERADMIN"),
+				),
+			},
 			{
 				ResourceName:      "snowflake_oauth_integration.test",
 				ImportState:       true,
@@ -41,7 +50,7 @@ func TestAcc_OAuthIntegration(t *testing.T) {
 	})
 }
 
-func oauthIntegrationConfig(name, oauthClient, clientType string) string {
+func oauthIntegrationConfig(name, oauthClient, clientType string, blockedRole string) string {
 	return fmt.Sprintf(`
 	resource "snowflake_oauth_integration" "test" {
 		name                         = "%s"
@@ -51,9 +60,9 @@ func oauthIntegrationConfig(name, oauthClient, clientType string) string {
 		enabled                      = true
   		oauth_issue_refresh_tokens   = true
   		oauth_refresh_token_validity = 3600
-  		blocked_roles_list           = ["SYSADMIN"]
+  		blocked_roles_list           = ["%s"]
 	}
-	`, name, oauthClient, clientType)
+	`, name, oauthClient, clientType, blockedRole)
 }
 
 func TestAcc_OAuthIntegrationTableau(t *testing.T) {
diff --git a/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/test.tf b/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/test.tf
new file mode 100644
index 0000000000..7942078c37
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/test.tf
@@ -0,0 +1,27 @@
+resource "snowflake_table" "t" {
+  database        = var.database
+  schema          = var.schema
+  name            = var.table_name
+  change_tracking = true
+  column {
+    name = "id"
+    type = "NUMBER(38,0)"
+  }
+  column {
+    name = "data"
+    type = "VARCHAR(16)"
+  }
+}
+
+resource "snowflake_dynamic_table" "dt" {
+  depends_on = [snowflake_table.t]
+  name       = var.name
+  database   = var.database
+  schema     = var.schema
+  target_lag {
+    maximum_duration = "2 minutes"
+  }
+  warehouse = var.warehouse
+  query     = var.query
+  comment   = var.comment
+}
diff --git a/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/variables.tf b/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/variables.tf
new file mode 100644
index 0000000000..5a6d6701d9
--- /dev/null
+++ b/pkg/resources/testdata/TestAcc_DynamicTable_issue2329/1/variables.tf
@@ -0,0 +1,27 @@
+variable "name" {
+  type = string
+}
+
+variable "database" {
+  type = string
+}
+
+variable "schema" {
+  type = string
+}
+
+variable "warehouse" {
+  type = string
+}
+
+variable "query" {
+  type = string
+}
+
+variable "comment" {
+  type = string
+}
+
+variable "table_name" {
+  type = string
+}
diff --git a/pkg/sdk/client.go b/pkg/sdk/client.go
index 700606f8a9..213c898ebd 100644
--- a/pkg/sdk/client.go
+++ b/pkg/sdk/client.go
@@ -73,7 +73,7 @@ type Client struct {
 	Shares                   Shares
 	Stages                   Stages
 	StorageIntegrations      StorageIntegrations
-  Streamlits               Streamlits
+	Streamlits               Streamlits
 	Streams                  Streams
 	Tables                   Tables
 	Tags                     Tags
diff --git a/pkg/sdk/poc/main.go b/pkg/sdk/poc/main.go
index 10edfb49fe..132bccd330 100644
--- a/pkg/sdk/poc/main.go
+++ b/pkg/sdk/poc/main.go
@@ -36,7 +36,7 @@ var definitionMapping = map[string]*generator.Interface{
 	"materialized_views_def.go":        sdk.MaterializedViewsDef,
 	"api_integrations_def.go":          sdk.ApiIntegrationsDef,
 	"notification_integrations_def.go": sdk.NotificationIntegrationsDef,
-  "streamlits_def.go":                sdk.StreamlitsDef,
+	"streamlits_def.go":                sdk.StreamlitsDef,
 }
 
 func main() {
diff --git a/pkg/sdk/testint/streamlits_integration_test.go b/pkg/sdk/testint/streamlits_integration_test.go
index e9a86e5c6b..1680389baa 100644
--- a/pkg/sdk/testint/streamlits_integration_test.go
+++ b/pkg/sdk/testint/streamlits_integration_test.go
@@ -55,7 +55,7 @@ func TestInt_Streamlits(t *testing.T) {
 	}
 
 	t.Run("create streamlit", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 
 		comment := random.StringN(4)
@@ -70,7 +70,7 @@ func TestInt_Streamlits(t *testing.T) {
 	})
 
 	t.Run("alter streamlit: set", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 		manifest := "manifest.yml"
 		e := createStreamlitHandle(t, stage, manifest)
@@ -84,7 +84,7 @@ func TestInt_Streamlits(t *testing.T) {
 	})
 
 	t.Run("alter function: rename", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 		e := createStreamlitHandle(t, stage, "manifest.yml")
 
@@ -107,7 +107,7 @@ func TestInt_Streamlits(t *testing.T) {
 	})
 
 	t.Run("show streamlit: with like", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 		e := createStreamlitHandle(t, stage, "manifest.yml")
 
@@ -118,7 +118,7 @@ func TestInt_Streamlits(t *testing.T) {
 	})
 
 	t.Run("show streamlit: terse with like", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 		e := createStreamlitHandle(t, stage, "manifest.yml")
 
@@ -139,7 +139,7 @@ func TestInt_Streamlits(t *testing.T) {
 	})
 
 	t.Run("describe streamlit", func(t *testing.T) {
-		stage, cleanupStage := createStage(t, client, databaseTest, schemaTest, random.AlphaN(4))
+		stage, cleanupStage := createStage(t, client, sdk.NewSchemaObjectIdentifier(TestDatabaseName, TestSchemaName, random.AlphaN(4)))
 		t.Cleanup(cleanupStage)
 
 		mainFile := "manifest.yml"