From 0ddf08cb2dd8b7535f4751970f37df884a8c24c4 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Mar 2024 14:50:12 -0400 Subject: [PATCH] Add framework function object parameter attribute requiredness tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/955 This adds acceptance tests that capture the linked issue around object parameter attribute requiredness with the existing behavior of Terraform and available functionality of the framework. These are being added as regression checks should framework functionality ever be introduced that either automatically or enables developers to make object attributes optional. It should be considered a breaking change should the existing function definition begin not causing an error, as provider developers may be reliant and desire this existing behavior for their use cases. Without `ErrorCheck` (and temporarily `TerraformVersionChecks` to workaround prerelease issues): ``` === CONT TestObjectFunction_Known_AttributeRequired_Error object_function_test.go:53: Step 1/1 error: Error running pre-apply plan: exit status 1 Error: Invalid function argument on terraform_plugin_test.tf line 13, in output "test": 13: value = provider::framework::object({ 14: "attr1" = "value1", 15: }) ├──────────────── │ while calling provider::framework::object(param1) Invalid value for "param1" parameter: attribute "attr2" is required. --- FAIL: TestObjectFunction_Known_AttributeRequired_Error (0.30s) ``` With `ErrorCheck`: ``` --- PASS: TestObjectFunction_Known_AttributeRequired_Error (0.48s) --- PASS: TestObjectFunction_Known_AttributeRequired_Null (0.53s) ``` --- .../object_function_test.go | 64 +++++++++++++++++++ .../object_function_test.go | 64 +++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/internal/framework5provider/object_function_test.go b/internal/framework5provider/object_function_test.go index f80f7f2..8f3b547 100644 --- a/internal/framework5provider/object_function_test.go +++ b/internal/framework5provider/object_function_test.go @@ -46,6 +46,70 @@ func TestObjectFunction_known(t *testing.T) { }) } +// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/955 +func TestObjectFunction_Known_AttributeRequired_Error(t *testing.T) { + t.Parallel() + + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_8_0), + }, + ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){ + "framework": providerserver.NewProtocol5WithError(New()), + }, + Steps: []resource.TestStep{ + { + Config: ` + output "test" { + value = provider::framework::object({ + "attr1" = "value1" + }) + }`, + // This error should always remain with the existing definition + // as provider developers may be reliant and desire this + // Terraform behavior. If new framework functionality is added + // to support optional object attributes, it should be tested + // separately. + ExpectError: regexp.MustCompile(`attribute "attr2" is required`), + }, + }, + }) +} + +// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/955 +func TestObjectFunction_Known_AttributeRequired_Null(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_8_0), + }, + ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){ + "framework": providerserver.NewProtocol5WithError(New()), + }, + Steps: []resource.TestStep{ + { + // AllowNullValue being disabled should not affect this + // configuration being valid. That setting only refers to the + // object itself. + Config: ` + output "test" { + value = provider::framework::object({ + "attr1" = "value1" + "attr2" = null + }) + }`, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownOutputValue("test", knownvalue.ObjectExact( + map[string]knownvalue.Check{ + "attr1": knownvalue.StringExact("value1"), + "attr2": knownvalue.Null(), + }, + )), + }, + }, + }, + }) +} + func TestObjectFunction_null(t *testing.T) { resource.UnitTest(t, resource.TestCase{ TerraformVersionChecks: []tfversion.TerraformVersionCheck{ diff --git a/internal/framework6provider/object_function_test.go b/internal/framework6provider/object_function_test.go index be34a9e..4a3460f 100644 --- a/internal/framework6provider/object_function_test.go +++ b/internal/framework6provider/object_function_test.go @@ -46,6 +46,70 @@ func TestObjectFunction_known(t *testing.T) { }) } +// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/955 +func TestObjectFunction_Known_AttributeRequired_Error(t *testing.T) { + t.Parallel() + + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_8_0), + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "framework": providerserver.NewProtocol6WithError(New()), + }, + Steps: []resource.TestStep{ + { + Config: ` + output "test" { + value = provider::framework::object({ + "attr1" = "value1" + }) + }`, + // This error should always remain with the existing definition + // as provider developers may be reliant and desire this + // Terraform behavior. If new framework functionality is added + // to support optional object attributes, it should be tested + // separately. + ExpectError: regexp.MustCompile(`attribute "attr2" is required`), + }, + }, + }) +} + +// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/955 +func TestObjectFunction_Known_AttributeRequired_Null(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_8_0), + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "framework": providerserver.NewProtocol6WithError(New()), + }, + Steps: []resource.TestStep{ + { + // AllowNullValue being disabled should not affect this + // configuration being valid. That setting only refers to the + // object itself. + Config: ` + output "test" { + value = provider::framework::object({ + "attr1" = "value1" + "attr2" = null + }) + }`, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownOutputValue("test", knownvalue.ObjectExact( + map[string]knownvalue.Check{ + "attr1": knownvalue.StringExact("value1"), + "attr2": knownvalue.Null(), + }, + )), + }, + }, + }, + }) +} + func TestObjectFunction_null(t *testing.T) { resource.UnitTest(t, resource.TestCase{ TerraformVersionChecks: []tfversion.TerraformVersionCheck{