package postgresflexalpha_test import ( "context" _ "embed" "fmt" "log" "math" "os" "regexp" "strconv" "strings" "testing" "time" "github.com/hashicorp/terraform-plugin-testing/compare" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" postgresflexalphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/internal/testutils" // The fwresource import alias is so there is no collision // with the more typical acceptance testing import: // "github.com/hashicorp/terraform-plugin-testing/helper/resource" fwresource "github.com/hashicorp/terraform-plugin-framework/resource" ) const ( pfx = "stackitprivatepreview_postgresflexalpha" dataPfx = "data.stackitprivatepreview_postgresflexalpha" singleFlavorID = "2.4" replicasFlavorID = "2.4-replica" ) func TestInstanceResourceSchema(t *testing.T) { // t.Parallel() ctx := context.Background() schemaRequest := fwresource.SchemaRequest{} schemaResponse := &fwresource.SchemaResponse{} // Instantiate the resource.Resource and call its Schema method postgresflexalphaInstance.NewInstanceResource().Schema(ctx, schemaRequest, schemaResponse) if schemaResponse.Diagnostics.HasError() { t.Fatalf("Schema method diagnostics: %+v", schemaResponse.Diagnostics) } // Validate the schema diagnostics := schemaResponse.Schema.ValidateImplementation(ctx) if diagnostics.HasError() { t.Fatalf("Schema validation diagnostics: %+v", diagnostics) } } func TestMain(m *testing.M) { testutils.Setup() code := m.Run() // shutdown() os.Exit(code) } func testAccPreCheck(t *testing.T) { if _, ok := os.LookupEnv("TF_ACC_PROJECT_ID"); !ok { t.Fatalf("could not find env var TF_ACC_PROJECT_ID") } } type resData struct { ServiceAccountFilePath string ProjectID string Region string Name string TfName string FlavorID *string BackupSchedule string UseEncryption bool KekKeyID string KekKeyRingID string KekKeyVersion uint8 KekServiceAccount string PerformanceClass string Replicas uint32 Size uint32 ACLStrings []string AccessScope string RetentionDays uint32 Version string Users []User Databases []Database DataSourceTest bool } type User struct { Name string ProjectID string Roles []string } type Database struct { Name string ProjectID string Owner string } func getExample() resData { name := acctest.RandomWithPrefix("tf-acc") return resData{ Region: os.Getenv("TF_ACC_REGION"), ServiceAccountFilePath: os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE"), ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Name: name, TfName: name, FlavorID: utils.Ptr(singleFlavorID), BackupSchedule: "0 0 * * *", UseEncryption: false, RetentionDays: 33, Replicas: 1, PerformanceClass: "premium-perf2-stackit", Size: 10, ACLStrings: []string{"0.0.0.0/0"}, AccessScope: "PUBLIC", Version: "17", } } func TestAccInstance(t *testing.T) { exData := getExample() exData.Version = "16" updNameData := exData updNameData.Name = "name-updated" updSizeData := exData updSizeData.Size = 25 updBackupSched := updSizeData // api should complain about more than one daily backup updBackupSched.BackupSchedule = "30 3 * * *" updNetACL := updBackupSched updNetACL.ACLStrings = append(updNetACL.ACLStrings, "192.168.0.0/24") updVersion := updNetACL updVersion.Version = "17" testItemID := testutils.ResStr(pfx, "instance", exData.TfName) compareValuesSame := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) t.Logf(" ... %s - %s", t.Name(), exData.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { PreConfig: func() { t.Logf("testing: %s - %s", t.Name(), "create and verify") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), ConfigStateChecks: []statecheck.StateCheck{ compareValuesSame.AddStateValue( testItemID, tfjsonpath.New("id"), ), statecheck.ExpectKnownValue( testItemID, tfjsonpath.New("is_deletable"), knownvalue.Bool(true), ), statecheck.ExpectKnownValue( testItemID, tfjsonpath.New("connection_info"), knownvalue.MapExact(map[string]knownvalue.Check{ "write": knownvalue.MapExact(map[string]knownvalue.Check{ "host": knownvalue.StringRegexp(regexp.MustCompile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}.postgresql.[a-z0-9]+.onstackit.cloud")), "port": knownvalue.Int32Func(func(v int32) error { if v < 0 { return fmt.Errorf("value is negative") } if v <= 1024 { return fmt.Errorf("value uses protected port range") } return nil }), }), }), ), }, Check: defaultNoEncInstanceTestChecks(testItemID, exData), }, // Second apply should not have changes { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "second apply") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), }, }, ConfigStateChecks: []statecheck.StateCheck{ compareValuesSame.AddStateValue( testItemID, tfjsonpath.New("id"), ), statecheck.ExpectKnownValue( testItemID, tfjsonpath.New("is_deletable"), knownvalue.Bool(true), ), }, }, // Refresh state test { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "refresh state") }, RefreshState: true, }, // Update name and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "update name") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updNameData, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( testItemID, "name", updNameData.Name, ), ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectNonEmptyPlan(), }, }, }, // Update size and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "update storage.size") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updSizeData, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( testItemID, "storage.size", strconv.Itoa(int(updSizeData.Size)), ), // network should contain 4 sub entries resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"), ), }, // Update backup schedule { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "update backup schedule") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updBackupSched, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( testItemID, "backup_schedule", updBackupSched.BackupSchedule, ), // network should contain 4 sub entries resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"), ), }, // Update network ACL { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "update network.acl") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updNetACL, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( testItemID, "backup_schedule", updBackupSched.BackupSchedule, ), // network should contain 4 sub entries resource.TestCheckResourceAttr(testItemID, "network.acl.#", "2"), ), }, // Update version { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "update version") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updVersion, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( testItemID, "version", updVersion.Version, ), ), }, // Import test // test instance imports { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "import instance") }, ResourceName: testItemID, // ImportStateIdPrefix: "", // ImportStateVerifyIdentifierAttribute: "id", ImportStateIdFunc: getInstanceTestID(exData.TfName), ImportStateKind: resource.ImportCommandWithID, ImportState: true, ImportStateVerify: true, }, }, }, ) } func TestAccInstanceHA(t *testing.T) { data := getExample() data.FlavorID = utils.Ptr(replicasFlavorID) data.Replicas = 3 testItemID := testutils.ResStr(pfx, "instance", data.TfName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "create and verify") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: defaultNoEncInstanceTestChecks(testItemID, data), }, }, }, ) } func TestAccInstanceWithUsers(t *testing.T) { data := getExample() userName := "testUser" data.Users = []User{ { Name: userName, ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Roles: []string{"login"}, }, } testItemID := testutils.ResStr(pfx, "instance", data.TfName) // TODO : implement check multiple users testUserItemID := testutils.ResStr(pfx, "user", userName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "create and verify") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( defaultNoEncInstanceTestChecks(testItemID, data), resource.TestCheckResourceAttr(testUserItemID, "name", userName), resource.TestCheckResourceAttrSet(testUserItemID, "id"), resource.TestCheckResourceAttr(testUserItemID, "roles.#", "1"), ), }, }, }, ) } func TestAccInstanceWithDatabases(t *testing.T) { data := getExample() dbName := "testdb" userName := "testUser" data.Users = []User{ { Name: userName, ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Roles: []string{"login"}, }, } data.Databases = []Database{ { Name: dbName, ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Owner: userName, }, } data.DataSourceTest = true testItemID := testutils.ResStr(pfx, "instance", data.TfName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "create and verify") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( defaultNoEncInstanceTestChecks(testItemID, data), // TODO - extract also to functions resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"), resource.TestCheckResourceAttrPair( testItemID, "project_id", testutils.ResStr(pfx, "user", userName), "project_id", ), resource.TestCheckResourceAttrPair( testItemID, "instance_id", testutils.ResStr(pfx, "user", userName), "instance_id", ), // TODO - extract also to functions resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"), resource.TestCheckResourceAttrPair( testItemID, "project_id", testutils.ResStr(pfx, "database", dbName), "project_id", ), resource.TestCheckResourceAttrPair( testItemID, "instance_id", testutils.ResStr(pfx, "database", dbName), "instance_id", ), ), }, // data source { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "datasource") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( // Instance data resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "instance", data.TfName), "project_id", data.ProjectID, ), resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "instance", data.TfName), "name", data.Name, ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "instance", data.TfName), "project_id", testutils.ResStr(pfx, "instance", data.TfName), "project_id", ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "database", dbName), "instance_id", testutils.ResStr(pfx, "instance", data.TfName), "instance_id", ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "user", userName), "instance_id", testutils.ResStr(pfx, "instance", data.TfName), "instance_id", ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "user", userName), "instance_id", testutils.ResStr(pfx, "user", userName), "instance_id", ), // User data resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "user", userName), "project_id", data.ProjectID, ), resource.TestCheckResourceAttrSet( testutils.ResStr(dataPfx, "user", userName), "user_id", ), resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "user", userName), "name", data.Users[0].Name, ), resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "user", userName), "roles.#", "1", ), resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "user", userName), "roles.0", data.Users[0].Roles[0], ), // Database data resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "database", dbName), "project_id", data.ProjectID, ), resource.TestCheckResourceAttr( testutils.ResStr(dataPfx, "database", dbName), "name", dbName, ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "database", dbName), "instance_id", testutils.ResStr(pfx, "database", dbName), "instance_id", ), resource.TestCheckResourceAttrPair( testutils.ResStr(dataPfx, "database", dbName), "owner", testutils.ResStr(dataPfx, "user", userName), "name", ), ), }, // test instance imports { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "import instance") }, ResourceName: testItemID, // ImportStateIdPrefix: "", ImportStateVerifyIdentifierAttribute: "id", ImportStateIdFunc: getInstanceTestID(data.TfName), ImportStateKind: resource.ImportCommandWithID, ImportState: true, ImportStateVerify: true, }, // test database imports { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "import database") }, ResourceName: testutils.ResStr(pfx, "database", dbName), // ImportStateIdPrefix: "", // ImportStateVerifyIdentifierAttribute: "id", ImportStateIdFunc: getDatabaseTestID(dbName), ImportStateKind: resource.ImportCommandWithID, ImportState: true, ImportStateVerify: true, }, // test user imports { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "import user") }, ResourceName: testutils.ResStr(pfx, "user", userName), // ImportStateIdPrefix: "", // ImportStateVerifyIdentifierAttribute: "id", ImportStateIdFunc: getUserTestID(userName), ImportStateKind: resource.ImportCommandWithID, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"password"}, }, }, }, ) } func TestAccEncryptedInstanceWithDatabases(t *testing.T) { encKekKeyID, ok := os.LookupEnv("TF_ACC_KEK_KEY_ID") if !ok || encKekKeyID == "" { t.Skip("env var TF_ACC_KEK_KEY_ID needed for encryption test") } encKekKeyRingID, ok := os.LookupEnv("TF_ACC_KEK_KEY_RING_ID") if !ok || encKekKeyRingID == "" { t.Skip("env var TF_ACC_KEK_KEY_RING_ID needed for encryption test") } encKekKeyVersion, ok := os.LookupEnv("TF_ACC_KEK_KEY_VERSION") if !ok || encKekKeyVersion == "" { t.Skip("env var TF_ACC_KEK_KEY_VERSION needed for encryption test") } encSvcAcc, ok := os.LookupEnv("TF_ACC_KEK_SERVICE_ACCOUNT") if !ok || encSvcAcc == "" { t.Skip("env var TF_ACC_KEK_SERVICE_ACCOUNT needed for encryption test") } data := getExample() data.UseEncryption = true data.KekKeyID = encKekKeyID data.KekKeyRingID = encKekKeyRingID data.KekServiceAccount = encSvcAcc encKekKeyVersionInt, err := strconv.Atoi(encKekKeyVersion) if err != nil { t.Errorf("error converting string to int") } if encKekKeyVersionInt > math.MaxUint8 { t.Errorf("value too large to convert to uint8") } data.KekKeyVersion = uint8(encKekKeyVersionInt) //nolint:gosec // handled above dbName := "testdb" userName := "testUser" data.Users = []User{ { Name: userName, ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Roles: []string{"login"}, }, } data.Databases = []Database{ { Name: dbName, ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Owner: userName, }, } testItemID := testutils.ResStr(pfx, "instance", data.TfName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { PreConfig: func() { t.Logf(" ... %s - %s", t.Name(), "create and verify") }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( defaultEncInstanceTestChecks(testItemID, data), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"), ), }, }, }, ) } func testAccCheckPostgresFlexDestroy(s *terraform.State) error { testutils.Setup() pID, ok := os.LookupEnv("TF_ACC_PROJECT_ID") if !ok { log.Fatalln("unable to read TF_ACC_PROJECT_ID") } ctx := context.Background() var client *v3alpha1api.APIClient var err error var region, projectID string region = testutils.Region if region == "" { region = "eu01" } projectID = pID if projectID == "" { return fmt.Errorf("projectID could not be determined in destroy function") } apiClientConfigOptions := []config.ConfigurationOption{ config.WithServiceAccountKeyPath(os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")), config.WithRegion(region), } if testutils.PostgresFlexCustomEndpoint != "" { apiClientConfigOptions = append( apiClientConfigOptions, config.WithEndpoint(testutils.PostgresFlexCustomEndpoint), ) } client, err = v3alpha1api.NewAPIClient(apiClientConfigOptions...) if err != nil { log.Fatalln(err) } instancesToDestroy := []string{} for _, rs := range s.RootModule().Resources { if rs.Type != "stackitprivatepreview_postgresflexalpha_instance" && rs.Type != "stackitprivatepreview_postgresflexbeta_instance" { continue } // instance terraform ID: = "[project_id],[region],[instance_id]" instanceID := strings.Split(rs.Primary.ID, core.Separator)[2] instancesToDestroy = append(instancesToDestroy, instanceID) } instancesResp, err := client.DefaultAPI.ListInstancesRequest(ctx, projectID, region). Size(100). Execute() if err != nil { return fmt.Errorf("getting instancesResp: %w", err) } items := instancesResp.GetInstances() for i := range items { if items[i].Id == "" { continue } if utils.Contains(instancesToDestroy, items[i].Id) { err := client.DefaultAPI.DeleteInstanceRequest(ctx, testutils.ProjectId, region, items[i].Id).Execute() if err != nil { return fmt.Errorf("deleting instance %s during CheckDestroy: %w", items[i].Id, err) } err = postgresflexalpha.DeleteInstanceWaitHandler( ctx, client.DefaultAPI, testutils.ProjectId, testutils.Region, items[i].Id, 30*time.Minute, 10*time.Second, ) if err != nil { return fmt.Errorf("deleting instance %s during CheckDestroy: waiting for deletion %w", items[i].Id, err) } } } return nil } func defaultNoEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { return resource.ComposeAggregateTestCheckFunc( defaultInstanceTestChecks(testItemID, data), // check absent attr resource.TestCheckNoResourceAttr(testItemID, "encryption"), resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"), resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_ring_id"), resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_version"), resource.TestCheckNoResourceAttr(testItemID, "encryption.service_account"), ) } func defaultEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { return resource.ComposeAggregateTestCheckFunc( defaultInstanceTestChecks(testItemID, data), // check absent attr resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"), resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"), resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_id", data.KekKeyID), resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_ring_id"), resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_ring_id", data.KekKeyRingID), resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_version"), resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_version", strconv.Itoa(int(data.KekKeyVersion))), resource.TestCheckResourceAttrSet(testItemID, "encryption.service_account"), resource.TestCheckResourceAttr(testItemID, "encryption.service_account", data.KekServiceAccount), ) } func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { // if AccessScope == SNA these are set if data.AccessScope == "SNA" { return resource.ComposeAggregateTestCheckFunc( basicInstanceTestChecks(testItemID, data), resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"), resource.TestCheckResourceAttrSet(testItemID, "network.router_address"), ) } // if AccessScope == PUBLIC these are empty - but they are set return resource.ComposeAggregateTestCheckFunc( basicInstanceTestChecks(testItemID, data), resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""), resource.TestCheckResourceAttr(testItemID, "network.router_address", ""), ) } func basicInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { return resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"), resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule), resource.TestCheckResourceAttr(testItemID, "connection_info.%", "1"), resource.TestCheckResourceAttr(testItemID, "connection_info.write.%", "2"), resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.host"), resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.port"), resource.TestCheckResourceAttrSet(testItemID, "flavor_id"), resource.TestCheckResourceAttr(testItemID, "flavor_id", data.FlavorID), resource.TestCheckResourceAttrSet(testItemID, "id"), resource.TestCheckResourceAttrSet(testItemID, "instance_id"), resource.TestCheckResourceAttrSet(testItemID, "is_deletable"), resource.TestCheckResourceAttr(testItemID, "is_deletable", "true"), resource.TestCheckResourceAttrSet(testItemID, "name"), resource.TestCheckResourceAttr(testItemID, "name", data.Name), // network params check resource.TestCheckResourceAttr(testItemID, "network.%", "4"), resource.TestCheckResourceAttrSet(testItemID, "network.access_scope"), resource.TestCheckResourceAttr(testItemID, "network.access_scope", data.AccessScope), // resource.TestCheckResourceAttrSet(testItemID, "network.acl"), resource.TestCheckResourceAttr(testItemID, "network.acl.#", strconv.Itoa(len(data.ACLStrings))), // instance_address and router_address are only checked in enc resource.TestCheckResourceAttrSet(testItemID, "project_id"), resource.TestCheckResourceAttr(testItemID, "project_id", data.ProjectID), resource.TestCheckResourceAttrSet(testItemID, "region"), resource.TestCheckResourceAttr(testItemID, "region", data.Region), resource.TestCheckResourceAttrSet(testItemID, "replicas"), resource.TestCheckResourceAttr(testItemID, "replicas", strconv.Itoa(int(data.Replicas))), resource.TestCheckResourceAttrSet(testItemID, "retention_days"), resource.TestCheckResourceAttr(testItemID, "retention_days", strconv.Itoa(int(data.RetentionDays))), resource.TestCheckResourceAttrSet(testItemID, "status"), resource.TestCheckResourceAttr(testItemID, "status", "READY"), // storage params check resource.TestCheckResourceAttr(testItemID, "storage.%", "2"), resource.TestCheckResourceAttrSet(testItemID, "storage.performance_class"), resource.TestCheckResourceAttr(testItemID, "storage.performance_class", data.PerformanceClass), resource.TestCheckResourceAttrSet(testItemID, "storage.size"), resource.TestCheckResourceAttr(testItemID, "storage.size", strconv.Itoa(int(data.Size))), resource.TestCheckResourceAttrSet(testItemID, "version"), resource.TestCheckResourceAttr(testItemID, "version", data.Version), ) } func getInstanceTestID(name string) func(s *terraform.State) (string, error) { return func(s *terraform.State) (string, error) { r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "instance", name)] if !ok { return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) } projectID, ok := r.Primary.Attributes["project_id"] if !ok { return "", fmt.Errorf("couldn't find attribute project_id") } region, ok := r.Primary.Attributes["region"] if !ok { return "", fmt.Errorf("couldn't find attribute region") } instanceID, ok := r.Primary.Attributes["instance_id"] if !ok { return "", fmt.Errorf("couldn't find attribute instance_id") } return fmt.Sprintf("%s,%s,%s", projectID, region, instanceID), nil } } func getDatabaseTestID(name string) func(s *terraform.State) (string, error) { return func(s *terraform.State) (string, error) { r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "database", name)] if !ok { return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) } projectID, ok := r.Primary.Attributes["project_id"] if !ok { return "", fmt.Errorf("couldn't find attribute project_id") } region, ok := r.Primary.Attributes["region"] if !ok { return "", fmt.Errorf("couldn't find attribute region") } instanceID, ok := r.Primary.Attributes["instance_id"] if !ok { return "", fmt.Errorf("couldn't find attribute instance_id") } databaseID, ok := r.Primary.Attributes["database_id"] if !ok { return "", fmt.Errorf("couldn't find attribute database_id") } return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, databaseID), nil } } func getUserTestID(name string) func(s *teraform.State) (string, error) { return func(s *terraform.State) (string, error) { r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "user", name)] if !ok { return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) } projectID, ok := r.Primary.Attributes["project_id"] if !ok { return "", fmt.Errorf("couldn't find attribute project_id") } region, ok := r.Primary.Attributes["region"] if !ok { return "", fmt.Errorf("couldn't find attribute region") } instanceID, ok := r.Primary.Attributes["instance_id"] if !ok { return "", fmt.Errorf("couldn't find attribute instance_id") } userID, ok := r.Primary.Attributes["user_id"] if !ok { return "", fmt.Errorf("couldn't find attribute user_id") } return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, userID), nil } }