From 2eb81867eafce8cf79eba82740c29de6b9f11dfb Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Thu, 16 Nov 2023 18:19:47 -0500 Subject: [PATCH] Add `WithoutResource` test helper We have to test that resources can be destroyed. However, for org tests, since we destroy everything (including the org), the test is bad since destroying the org destroys everything within To help with this, this new helper will allow to add a step in org tests where we keep the org, but remove the actual resource on which we want to test deletion To test the behavior, I made the role resource tests use this instead of a `if` and I added a test step for the team resource --- .../resources/grafana/resource_role_test.go | 18 ++---- .../resources/grafana/resource_team_test.go | 10 ++- internal/testutils/resources.go | 25 ++++++++ internal/testutils/resources_test.go | 63 +++++++++++++++++++ 4 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 internal/testutils/resources.go create mode 100644 internal/testutils/resources_test.go diff --git a/internal/resources/grafana/resource_role_test.go b/internal/resources/grafana/resource_role_test.go index 8a81e8c11..eb5f850dd 100644 --- a/internal/resources/grafana/resource_role_test.go +++ b/internal/resources/grafana/resource_role_test.go @@ -131,13 +131,10 @@ func TestAccRole_inOrg(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ ProviderFactories: testutils.ProviderFactories, - CheckDestroy: resource.ComposeTestCheckFunc( - roleCheckExists.destroyed(&role, &org), - orgCheckExists.destroyed(&org, nil), - ), + CheckDestroy: orgCheckExists.destroyed(&org, nil), Steps: []resource.TestStep{ { - Config: roleInOrg(name, true), + Config: roleInOrg(name), Check: resource.ComposeTestCheckFunc( roleCheckExists.exists("grafana_role.test", &role), orgCheckExists.exists("grafana_organization.test", &org), @@ -153,9 +150,9 @@ func TestAccRole_inOrg(t *testing.T) { resource.TestCheckResourceAttr("grafana_role.test", "hidden", "false"), ), }, - // Test destroying role within org + // Test destroying role within org. Org keeps existing but role is gone. { - Config: roleInOrg(name, false), + Config: testutils.WithoutResource(t, roleInOrg(name), "grafana_role.test"), Check: resource.ComposeTestCheckFunc( roleCheckExists.destroyed(&role, &org), orgCheckExists.exists("grafana_organization.test", &org), @@ -165,14 +162,12 @@ func TestAccRole_inOrg(t *testing.T) { }) } -func roleInOrg(name string, roleExists bool) string { +func roleInOrg(name string) string { def := fmt.Sprintf(` resource "grafana_organization" "test" { name = "%s" -}`, name) +} - if roleExists { - def += fmt.Sprintf(` resource "grafana_role" "test" { org_id = grafana_organization.test.id name = "%[1]s" @@ -184,7 +179,6 @@ resource "grafana_role" "test" { hidden = false auto_increment_version = true }`, name) - } return def } diff --git a/internal/resources/grafana/resource_team_test.go b/internal/resources/grafana/resource_team_test.go index 5d6f9859e..bb31a4ab7 100644 --- a/internal/resources/grafana/resource_team_test.go +++ b/internal/resources/grafana/resource_team_test.go @@ -290,7 +290,7 @@ func TestAccResourceTeam_InOrg(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ ProviderFactories: testutils.ProviderFactories, - CheckDestroy: teamCheckExists.destroyed(&team, &org), + CheckDestroy: orgCheckExists.destroyed(&org, nil), Steps: []resource.TestStep{ { Config: testAccTeamInOrganization(name), @@ -303,6 +303,14 @@ func TestAccResourceTeam_InOrg(t *testing.T) { checkResourceIsInOrg("grafana_team.test", "grafana_organization.test"), ), }, + // Test destroying team within org. Org keeps existing but team is gone. + { + Config: testutils.WithoutResource(t, testAccTeamInOrganization(name), "grafana_team.test"), + Check: resource.ComposeTestCheckFunc( + teamCheckExists.destroyed(&team, &org), + orgCheckExists.exists("grafana_organization.test", &org), + ), + }, }, }) } diff --git a/internal/testutils/resources.go b/internal/testutils/resources.go new file mode 100644 index 000000000..dc22e5724 --- /dev/null +++ b/internal/testutils/resources.go @@ -0,0 +1,25 @@ +package testutils + +import ( + "strings" + "testing" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclwrite" +) + +// WithoutResource removes a resource from a Terraform configuration. +func WithoutResource(t *testing.T, tfCode string, resourceName string) string { + tfConfig, err := hclwrite.ParseConfig([]byte(tfCode), "", hcl.Pos{Line: 1, Column: 1}) + if err != nil { + t.Fatalf("failed to parse HCL: %v", err) + } + + block := tfConfig.Body().FirstMatchingBlock("resource", strings.Split(resourceName, ".")) + if block == nil { + t.Fatalf("failed to find resource %q", resourceName) + } + tfConfig.Body().RemoveBlock(block) + + return string(tfConfig.Bytes()) +} diff --git a/internal/testutils/resources_test.go b/internal/testutils/resources_test.go new file mode 100644 index 000000000..e3707705b --- /dev/null +++ b/internal/testutils/resources_test.go @@ -0,0 +1,63 @@ +package testutils + +import "testing" + +func TestWithoutResource(t *testing.T) { + t.Parallel() + + input := `resource "grafana_organization" "test" { + name = "test" + } + + resource "grafana_folder" "test" { + org_id = grafana_organization.test.id + title = "test" + } + + resource "grafana_rule_group" "test" { + org_id = grafana_organization.test.id + name = "test" + folder_uid = grafana_folder.test.uid + interval_seconds = 360 + rule { + name = "My Alert Rule 1" + for = "2m" + condition = "B" + no_data_state = "NoData" + exec_err_state = "Alerting" + is_paused = false + data { + ref_id = "A" + query_type = "" + relative_time_range { + from = 600 + to = 0 + } + datasource_uid = "PD8C576611E62080A" + model = jsonencode({ + hide = false + intervalMs = 1000 + maxDataPoints = 43200 + refId = "A" + }) + } + } + }` + + expected := `resource "grafana_organization" "test" { + name = "test" +} + +resource "grafana_folder" "test" { + org_id = grafana_organization.test.id + title = "test" +} + +` + + actual := WithoutResource(t, input, "grafana_rule_group.test") + + if actual != expected { + t.Errorf("expected:\n%q\n\nactual:\n%q", expected, actual) + } +}