diff --git a/internal/acctest/template_test.go b/internal/acctest/template_test.go index 32292cb2f..6a4ccb430 100644 --- a/internal/acctest/template_test.go +++ b/internal/acctest/template_test.go @@ -8,6 +8,180 @@ import ( "github.com/stretchr/testify/assert" ) +func TestCompositionBuilder_SingleResource(t *testing.T) { + registry := NewTemplateRegistry("test") + + template := `resource "aiven_project" "example_project" { + project = "{{ .project_name }}" +}` + registry.MustAddTemplate(t, "project", template) + + builder := registry.NewCompositionBuilder() + builder.Add("project", map[string]any{ + "project_name": "test-project", + }) + + expected := `resource "aiven_project" "example_project" { + project = "test-project" +}` + + result := builder.MustRender(t) + assert.Equal(t, normalizeHCL(expected), normalizeHCL(result)) +} + +func TestCompositionBuilder_TwoIndependentResources(t *testing.T) { + registry := NewTemplateRegistry("test") + + registry.MustAddTemplate(t, "org_unit", `resource "aiven_organizational_unit" "example_unit" { + name = "{{ .name }}" +}`) + registry.MustAddTemplate(t, "billing_group", `resource "aiven_billing_group" "example_billing_group" { + name = "{{ .name }}" + billing_currency = "{{ .currency }}" +}`) + + builder := registry.NewCompositionBuilder() + builder.Add("org_unit", map[string]any{ + "name": "Example Unit", + }) + builder.Add("billing_group", map[string]any{ + "name": "Example Billing", + "currency": "USD", + }) + + expected := `resource "aiven_organizational_unit" "example_unit" { + name = "Example Unit" +} +resource "aiven_billing_group" "example_billing_group" { + name = "Example Billing" + billing_currency = "USD" +}` + + result := builder.MustRender(t) + assert.Equal(t, normalizeHCL(expected), normalizeHCL(result)) +} + +func TestCompositionBuilder_DependentResources(t *testing.T) { + registry := NewTemplateRegistry("test") + + registry.MustAddTemplate(t, "billing_group", `resource "aiven_billing_group" "example_billing_group" { + name = "{{ .name }}" + billing_currency = "USD" +}`) + registry.MustAddTemplate(t, "project", `resource "aiven_project" "example_project" { + project = "{{ .name }}" + billing_group = aiven_billing_group.example_billing_group.id +}`) + + builder := registry.NewCompositionBuilder() + builder.Add("billing_group", map[string]any{ + "name": "example-billing", + }) + builder.Add("project", map[string]any{ + "name": "example-project", + }) + + expected := `resource "aiven_billing_group" "example_billing_group" { + name = "example-billing" + billing_currency = "USD" +} +resource "aiven_project" "example_project" { + project = "example-project" + billing_group = aiven_billing_group.example_billing_group.id +}` + + result := builder.MustRender(t) + assert.Equal(t, normalizeHCL(expected), normalizeHCL(result)) +} + +func TestCompositionBuilder_ConditionalResource(t *testing.T) { + registry := NewTemplateRegistry("test") + + registry.MustAddTemplate(t, "project", `resource "aiven_project" "example_project" { + project = "{{ .name }}" +}`) + registry.MustAddTemplate(t, "redis", `resource "aiven_redis" "redis1" { + project = aiven_project.example_project.project + service_name = "{{ .name }}" + plan = "{{ .plan }}" +}`) + + tests := []struct { + name string + includeRedis bool + expectedOutput string + }{ + { + name: "with_redis", + includeRedis: true, + expectedOutput: `resource "aiven_project" "example_project" { + project = "test-project" +} +resource "aiven_redis" "redis1" { + project = aiven_project.example_project.project + service_name = "test-redis" + plan = "business-4" +}`, + }, + { + name: "without_redis", + includeRedis: false, + expectedOutput: `resource "aiven_project" "example_project" { + project = "test-project" +}`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + builder := registry.NewCompositionBuilder() + + builder.Add("project", map[string]any{ + "name": "test-project", + }) + + builder.AddIf(tt.includeRedis, "redis", map[string]any{ + "name": "test-redis", + "plan": "business-4", + }) + + result := builder.MustRender(t) + assert.Equal(t, normalizeHCL(tt.expectedOutput), normalizeHCL(result)) + }) + } +} + +func TestCompositionBuilder_DataSourceAndResource(t *testing.T) { + registry := NewTemplateRegistry("test") + + registry.MustAddTemplate(t, "org_data", `data "aiven_organization" "main" { + name = "{{ .name }}" +}`) + registry.MustAddTemplate(t, "project", `resource "aiven_project" "example_project" { + project = "{{ .name }}" + organization_id = data.aiven_organization.main.id +}`) + + builder := registry.NewCompositionBuilder() + builder.Add("org_data", map[string]any{ + "name": "example-org", + }) + builder.Add("project", map[string]any{ + "name": "example-project", + }) + + expected := `data "aiven_organization" "main" { + name = "example-org" +} +resource "aiven_project" "example_project" { + project = "example-project" + organization_id = data.aiven_organization.main.id +}` + + result := builder.MustRender(t) + assert.Equal(t, normalizeHCL(expected), normalizeHCL(result)) +} + func TestCompositionBuilder(t *testing.T) { tests := []struct { name string @@ -192,190 +366,6 @@ resource "aiven_kafka_user" "example_service_user" { } } -func TestCompositionBuilderConditionalResources(t *testing.T) { - registry := NewTemplateRegistry("test") - - // Add templates for different resources - templates := map[string]string{ - "organization_data": `data "aiven_organization" "main" { - name = "{{ .org_name }}" -}`, - "billing_group": `resource "aiven_billing_group" "example_billing_group" { - name = "{{ .name }}" - billing_currency = "{{ .currency }}" - vat_id = "{{ .vat_id }}" - parent_id = data.aiven_organization.main.id -}`, - "project": `resource "aiven_project" "example_project" { - project = "{{ .project_name }}" - billing_group = aiven_billing_group.example_billing_group.id -}`, - "org_unit": `resource "aiven_organizational_unit" "example_unit" { - name = "{{ .name }}" - parent_id = data.aiven_organization.main.id -}`, - "redis": `resource "aiven_redis" "redis1" { - project = aiven_project.example_project.project - cloud_name = "{{ .cloud_name }}" - plan = "{{ .plan }}" - service_name = "{{ .service_name }}" - maintenance_window_dow = "{{ .maintenance_window_dow }}" - maintenance_window_time = "{{ .maintenance_window_time }}" - redis_user_config { - redis_maxmemory_policy = "{{ .maxmemory_policy }}" - public_access { - redis = {{ .public_access }} - } - } -}`} - - // Add all templates to registry - for key, tmpl := range templates { - registry.MustAddTemplate(t, key, tmpl) - } - - tests := []struct { - name string - includeBilling bool - includeOrgUnit bool - includeRedis bool - expectedResources int - config map[string]map[string]any - expectedOutput string - }{ - { - name: "all_resources", - includeBilling: true, - includeOrgUnit: true, - includeRedis: true, - expectedResources: 5, // data source + 4 resources - config: map[string]map[string]any{ - "organization_data": { - "org_name": "my-organization", - }, - "billing_group": { - "name": "example-billing-group", - "currency": "USD", - "vat_id": "123ABC", - }, - "project": { - "project_name": "example-project", - }, - "org_unit": { - "name": "Example organizational unit", - }, - "redis": { - "cloud_name": "google-europe-west1", - "plan": "business-4", - "service_name": "my-redis1", - "maintenance_window_dow": "monday", - "maintenance_window_time": "10:00:00", - "maxmemory_policy": "allkeys-random", - "public_access": true, - }, - }, - expectedOutput: `data "aiven_organization" "main" { - name = "my-organization" -} -resource "aiven_billing_group" "example_billing_group" { - name = "example-billing-group" - billing_currency = "USD" - vat_id = "123ABC" - parent_id = data.aiven_organization.main.id -} -resource "aiven_project" "example_project" { - project = "example-project" - billing_group = aiven_billing_group.example_billing_group.id -} -resource "aiven_organizational_unit" "example_unit" { - name = "Example organizational unit" - parent_id = data.aiven_organization.main.id -} -resource "aiven_redis" "redis1" { - project = aiven_project.example_project.project - cloud_name = "google-europe-west1" - plan = "business-4" - service_name = "my-redis1" - maintenance_window_dow = "monday" - maintenance_window_time = "10:00:00" - redis_user_config { - redis_maxmemory_policy = "allkeys-random" - public_access { - redis = true - } - } -}`, - }, - { - name: "minimal_setup", - includeBilling: true, - includeOrgUnit: false, - includeRedis: false, - expectedResources: 3, // data source + 2 resources - config: map[string]map[string]any{ - "organization_data": { - "org_name": "my-organization", - }, - "billing_group": { - "name": "example-billing-group", - "currency": "USD", - "vat_id": "123ABC", - }, - "project": { - "project_name": "example-project", - }, - }, - expectedOutput: `data "aiven_organization" "main" { - name = "my-organization" -} -resource "aiven_billing_group" "example_billing_group" { - name = "example-billing-group" - billing_currency = "USD" - vat_id = "123ABC" - parent_id = data.aiven_organization.main.id -} -resource "aiven_project" "example_project" { - project = "example-project" - billing_group = aiven_billing_group.example_billing_group.id -}`, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - builder := registry.NewCompositionBuilder() - - // Always add organization data source - builder.Add("organization_data", tt.config["organization_data"]) - - // Add billing group and project (they go together) - if tt.includeBilling { - builder.Add("billing_group", tt.config["billing_group"]) - builder.Add("project", tt.config["project"]) - } - - // Conditionally add organizational unit - builder.AddIf(tt.includeOrgUnit, "org_unit", tt.config["org_unit"]) - - // Conditionally add Redis service - builder.AddIf(tt.includeRedis, "redis", tt.config["redis"]) - - result := builder.MustRender(t) - - // Verify the rendered output - assert.Equal(t, - normalizeHCL(tt.expectedOutput), - normalizeHCL(result), - "Rendered template should match expected output", - ) - - // Count number of resources in output - resourceCount := strings.Count(result, "resource") + strings.Count(result, "data") - assert.Equal(t, tt.expectedResources, resourceCount, "Number of resources should match expected count") - }) - } -} - // normalizeHCL function remains the same func normalizeHCL(s string) string { // Remove all whitespace between blocks