diff --git a/go.mod b/go.mod index dfec338..01e5f83 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/hashicorp/terraform-plugin-go v0.22.1 github.com/hashicorp/terraform-plugin-mux v0.15.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 - github.com/hashicorp/terraform-plugin-testing v1.7.0 + github.com/hashicorp/terraform-plugin-testing v1.7.1-0.20240325220100-c294752cca7f github.com/zclconf/go-cty v1.14.3 ) diff --git a/go.sum b/go.sum index eacce0b..5f098b9 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/hashicorp/terraform-plugin-mux v0.15.0 h1:+/+lDx0WUsIOpkAmdwBIoFU8UP9 github.com/hashicorp/terraform-plugin-mux v0.15.0/go.mod h1:9ezplb1Dyq394zQ+ldB0nvy/qbNAz3mMoHHseMTMaKo= github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0 h1:qHprzXy/As0rxedphECBEQAh3R4yp6pKksKHcqZx5G8= github.com/hashicorp/terraform-plugin-sdk/v2 v2.33.0/go.mod h1:H+8tjs9TjV2w57QFVSMBQacf8k/E1XwLXGCARgViC6A= -github.com/hashicorp/terraform-plugin-testing v1.7.0 h1:I6aeCyZ30z4NiI3tzyDoO6fS7YxP5xSL1ceOon3gTe8= -github.com/hashicorp/terraform-plugin-testing v1.7.0/go.mod h1:sbAreCleJNOCz+y5vVHV8EJkIWZKi/t4ndKiUjM9vao= +github.com/hashicorp/terraform-plugin-testing v1.7.1-0.20240325220100-c294752cca7f h1:KANyvm9GwKRS1xkaYge+6a9NUhLwlR5kUz5kOT9mw00= +github.com/hashicorp/terraform-plugin-testing v1.7.1-0.20240325220100-c294752cca7f/go.mod h1:Vf0AwgzPP6M/yopLkHMdIT4aG3V66hS14Emv2UvRsNs= github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM= github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= diff --git a/internal/cornertesting/expect_output_type_state_check.go b/internal/cornertesting/expect_output_type_state_check.go index 66a18b9..a85df21 100644 --- a/internal/cornertesting/expect_output_type_state_check.go +++ b/internal/cornertesting/expect_output_type_state_check.go @@ -49,7 +49,7 @@ func (e expectOutputType) CheckState(ctx context.Context, req statecheck.CheckSt } if !output.Type.Equals(e.expectedType) { - resp.Error = fmt.Errorf("expected %q output type to be %q, got %q", e.outputAddress, output.Type.FriendlyName(), e.expectedType.FriendlyName()) + resp.Error = fmt.Errorf("expected %q output type to be %q, got %q", e.outputAddress, e.expectedType.FriendlyName(), output.Type.FriendlyName()) } } diff --git a/internal/framework5provider/dynamic_schema_resource_test.go b/internal/framework5provider/dynamic_schema_resource_test.go index 942adfe..3d1469b 100644 --- a/internal/framework5provider/dynamic_schema_resource_test.go +++ b/internal/framework5provider/dynamic_schema_resource_test.go @@ -107,8 +107,7 @@ func TestDynamicSchemaResource_DynamicAttribute(t *testing.T) { "attribute_one": knownvalue.StringExact("value1"), "attribute_two": knownvalue.Bool(false), "attribute_three": knownvalue.NumberExact(big.NewFloat(1234.5)), - // ListExact can be used despite the underlying type being a tuple[bool, number] - "attribute_four": knownvalue.ListExact( + "attribute_four": knownvalue.TupleExact( []knownvalue.Check{ knownvalue.Bool(true), knownvalue.NumberExact(big.NewFloat(1234.5)), diff --git a/internal/framework5provider/dynamic_variadic_function.go b/internal/framework5provider/dynamic_variadic_function.go index 19f93b9..cb074f8 100644 --- a/internal/framework5provider/dynamic_variadic_function.go +++ b/internal/framework5provider/dynamic_variadic_function.go @@ -37,22 +37,19 @@ func (f DynamicVariadicFunction) Run(ctx context.Context, req function.RunReques resp.Error = req.Arguments.Get(ctx, &varg) - dynVals := make([]attr.Value, 0) + tupleTypes := make([]attr.Type, 0) + tupleValues := make([]attr.Value, 0) for _, arg := range varg { - dynVals = append(dynVals, types.DynamicValue(arg.UnderlyingValue())) + tupleTypes = append(tupleTypes, arg.UnderlyingValue().Type(ctx)) + tupleValues = append(tupleValues, arg.UnderlyingValue()) } - // Despite types.List not fully supporting dynamic types, in this restricted scenario it will work fine - // as long as all the dynamic types coming in are the same. - // - // TODO: Switch this to a tuple once `terraform-plugin-testing` bug has been fixed with Tuple output: - // - https://github.com/hashicorp/terraform-plugin-testing/issues/310 - listReturn, diags := types.ListValue(types.DynamicType, dynVals) + tupleReturn, diags := types.TupleValue(tupleTypes, tupleValues) if diags.HasError() { resp.Error = function.FuncErrorFromDiags(ctx, diags) return } - resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, types.DynamicValue(listReturn))) + resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, types.DynamicValue(tupleReturn))) } diff --git a/internal/framework5provider/dynamic_variadic_function_test.go b/internal/framework5provider/dynamic_variadic_function_test.go index d9a9df2..47f48fe 100644 --- a/internal/framework5provider/dynamic_variadic_function_test.go +++ b/internal/framework5provider/dynamic_variadic_function_test.go @@ -36,9 +36,8 @@ func TestDynamicVariadicFunction_value_zero(t *testing.T) { value = provider::framework::dynamic_variadic() }`, ConfigStateChecks: []statecheck.StateCheck{ - // Since no arguments were passed in to determine the type, the list will be dynamic - cornertesting.ExpectOutputType("test", cty.List(cty.DynamicPseudoType)), - statecheck.ExpectKnownOutputValue("test", knownvalue.ListExact([]knownvalue.Check{})), + cornertesting.ExpectOutputType("test", cty.Tuple([]cty.Type{})), + statecheck.ExpectKnownOutputValue("test", knownvalue.TupleExact([]knownvalue.Check{})), }, }, }, @@ -61,9 +60,15 @@ func TestDynamicVariadicFunction_value_one(t *testing.T) { value = provider::framework::dynamic_variadic("one") }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType("test", cty.List(cty.String)), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("one"), }, @@ -91,9 +96,16 @@ func TestDynamicVariadicFunction_value_multiple_same_type_primitive(t *testing.T value = provider::framework::dynamic_variadic("one", "two") }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType("test", cty.List(cty.String)), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("one"), knownvalue.StringExact("two"), @@ -125,18 +137,24 @@ func TestDynamicVariadicFunction_value_multiple_same_type_complex(t *testing.T) ) }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType( - "test", - cty.List( - cty.Object(map[string]cty.Type{ - "a": cty.Number, - "b": cty.Bool, - "c": cty.String, - }), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.Object(map[string]cty.Type{ + "a": cty.Number, + "b": cty.Bool, + "c": cty.String, + }), + cty.Object(map[string]cty.Type{ + "a": cty.Number, + "b": cty.Bool, + "c": cty.String, + }), + }, ), ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.ObjectExact( map[string]knownvalue.Check{ @@ -161,40 +179,46 @@ func TestDynamicVariadicFunction_value_multiple_same_type_complex(t *testing.T) }) } -// This test can't be completed until the `dynamic_variadic` function implementation uses a tuple return. -// A `terraform-plugin-testing` bug is causing a panic when an output value is a tuple. -// - https://github.com/hashicorp/terraform-plugin-testing/issues/310 -// -// TODO: Uncomment this test when the upstream tuple bug is fixed and the function implementation switches to using a tuple. -// -// func TestDynamicVariadicFunction_value_multiple_different_type(t *testing.T) { -// resource.UnitTest(t, resource.TestCase{ -// TerraformVersionChecks: []tfversion.TerraformVersionCheck{ -// // TODO: Replace with the stable v1.8.0 release when available -// tfversion.SkipBelow(version.Must(version.NewVersion("v1.8.0-rc1"))), -// }, -// ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){ -// "framework": providerserver.NewProtocol5WithError(New()), -// }, -// Steps: []resource.TestStep{ -// { -// Config: ` -// output "test" { -// value = provider::framework::dynamic_variadic(true, "string", 1234.5) -// }`, -// ConfigStateChecks: []statecheck.StateCheck{ -// cornertesting.ExpectOutputType("test", cty.Tuple([]cty.Type{cty.Bool, cty.String, cty.Number})), -// // ListExact can be used despite the underlying type being a tuple[bool, string, number] -// statecheck.ExpectKnownOutputValue("test", knownvalue.ListExact([]knownvalue.Check{ -// knownvalue.Bool(true), -// knownvalue.StringExact("string"), -// knownvalue.NumberExact(big.NewFloat(1234.5)), -// })), -// }, -// }, -// }, -// }) -// } +func TestDynamicVariadicFunction_value_multiple_different_type(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + // TODO: Replace with the stable v1.8.0 release when available + tfversion.SkipBelow(version.Must(version.NewVersion("v1.8.0-rc1"))), + }, + ProtoV5ProviderFactories: map[string]func() (tfprotov5.ProviderServer, error){ + "framework": providerserver.NewProtocol5WithError(New()), + }, + Steps: []resource.TestStep{ + { + Config: ` + output "test" { + value = provider::framework::dynamic_variadic(true, "string", 1234.5) + }`, + ConfigStateChecks: []statecheck.StateCheck{ + cornertesting.ExpectOutputType( + "test", + cty.Tuple( + []cty.Type{ + cty.Bool, + cty.String, + cty.Number, + }, + ), + ), + statecheck.ExpectKnownOutputValue("test", + knownvalue.TupleExact( + []knownvalue.Check{ + knownvalue.Bool(true), + knownvalue.StringExact("string"), + knownvalue.NumberExact(big.NewFloat(1234.5)), + }, + ), + ), + }, + }, + }, + }) +} func TestDynamicVariadicFunction_null(t *testing.T) { resource.UnitTest(t, resource.TestCase{ @@ -268,8 +292,15 @@ func TestDynamicVariadicFunction_unknown(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("test-value"), }, diff --git a/internal/framework6provider/dynamic_variadic_function.go b/internal/framework6provider/dynamic_variadic_function.go index 19f93b9..cb074f8 100644 --- a/internal/framework6provider/dynamic_variadic_function.go +++ b/internal/framework6provider/dynamic_variadic_function.go @@ -37,22 +37,19 @@ func (f DynamicVariadicFunction) Run(ctx context.Context, req function.RunReques resp.Error = req.Arguments.Get(ctx, &varg) - dynVals := make([]attr.Value, 0) + tupleTypes := make([]attr.Type, 0) + tupleValues := make([]attr.Value, 0) for _, arg := range varg { - dynVals = append(dynVals, types.DynamicValue(arg.UnderlyingValue())) + tupleTypes = append(tupleTypes, arg.UnderlyingValue().Type(ctx)) + tupleValues = append(tupleValues, arg.UnderlyingValue()) } - // Despite types.List not fully supporting dynamic types, in this restricted scenario it will work fine - // as long as all the dynamic types coming in are the same. - // - // TODO: Switch this to a tuple once `terraform-plugin-testing` bug has been fixed with Tuple output: - // - https://github.com/hashicorp/terraform-plugin-testing/issues/310 - listReturn, diags := types.ListValue(types.DynamicType, dynVals) + tupleReturn, diags := types.TupleValue(tupleTypes, tupleValues) if diags.HasError() { resp.Error = function.FuncErrorFromDiags(ctx, diags) return } - resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, types.DynamicValue(listReturn))) + resp.Error = function.ConcatFuncErrors(resp.Error, resp.Result.Set(ctx, types.DynamicValue(tupleReturn))) } diff --git a/internal/framework6provider/dynamic_variadic_function_test.go b/internal/framework6provider/dynamic_variadic_function_test.go index 2a46d57..f693ab0 100644 --- a/internal/framework6provider/dynamic_variadic_function_test.go +++ b/internal/framework6provider/dynamic_variadic_function_test.go @@ -36,9 +36,8 @@ func TestDynamicVariadicFunction_value_zero(t *testing.T) { value = provider::framework::dynamic_variadic() }`, ConfigStateChecks: []statecheck.StateCheck{ - // Since no arguments were passed in to determine the type, the list will be dynamic - cornertesting.ExpectOutputType("test", cty.List(cty.DynamicPseudoType)), - statecheck.ExpectKnownOutputValue("test", knownvalue.ListExact([]knownvalue.Check{})), + cornertesting.ExpectOutputType("test", cty.Tuple([]cty.Type{})), + statecheck.ExpectKnownOutputValue("test", knownvalue.TupleExact([]knownvalue.Check{})), }, }, }, @@ -61,9 +60,15 @@ func TestDynamicVariadicFunction_value_one(t *testing.T) { value = provider::framework::dynamic_variadic("one") }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType("test", cty.List(cty.String)), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("one"), }, @@ -91,9 +96,16 @@ func TestDynamicVariadicFunction_value_multiple_same_type_primitive(t *testing.T value = provider::framework::dynamic_variadic("one", "two") }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType("test", cty.List(cty.String)), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("one"), knownvalue.StringExact("two"), @@ -125,18 +137,24 @@ func TestDynamicVariadicFunction_value_multiple_same_type_complex(t *testing.T) ) }`, ConfigStateChecks: []statecheck.StateCheck{ - cornertesting.ExpectOutputType( - "test", - cty.List( - cty.Object(map[string]cty.Type{ - "a": cty.Number, - "b": cty.Bool, - "c": cty.String, - }), + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.Object(map[string]cty.Type{ + "a": cty.Number, + "b": cty.Bool, + "c": cty.String, + }), + cty.Object(map[string]cty.Type{ + "a": cty.Number, + "b": cty.Bool, + "c": cty.String, + }), + }, ), ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.ObjectExact( map[string]knownvalue.Check{ @@ -161,40 +179,46 @@ func TestDynamicVariadicFunction_value_multiple_same_type_complex(t *testing.T) }) } -// This test can't be completed until the `dynamic_variadic` function implementation uses a tuple return. -// A `terraform-plugin-testing` bug is causing a panic when an output value is a tuple. -// - https://github.com/hashicorp/terraform-plugin-testing/issues/310 -// -// TODO: Uncomment this test when the upstream tuple bug is fixed and the function implementation switches to using a tuple. -// -// func TestDynamicVariadicFunction_value_multiple_different_type(t *testing.T) { -// resource.UnitTest(t, resource.TestCase{ -// TerraformVersionChecks: []tfversion.TerraformVersionCheck{ -// // TODO: Replace with the stable v1.8.0 release when available -// tfversion.SkipBelow(version.Must(version.NewVersion("v1.8.0-rc1"))), -// }, -// ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ -// "framework": providerserver.NewProtocol6WithError(New()), -// }, -// Steps: []resource.TestStep{ -// { -// Config: ` -// output "test" { -// value = provider::framework::dynamic_variadic(true, "string", 1234.5) -// }`, -// ConfigStateChecks: []statecheck.StateCheck{ -// cornertesting.ExpectOutputType("test", cty.Tuple([]cty.Type{cty.Bool, cty.String, cty.Number})), -// // ListExact can be used despite the underlying type being a tuple[bool, string, number] -// statecheck.ExpectKnownOutputValue("test", knownvalue.ListExact([]knownvalue.Check{ -// knownvalue.Bool(true), -// knownvalue.StringExact("string"), -// knownvalue.NumberExact(big.NewFloat(1234.5)), -// })), -// }, -// }, -// }, -// }) -// } +func TestDynamicVariadicFunction_value_multiple_different_type(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + // TODO: Replace with the stable v1.8.0 release when available + tfversion.SkipBelow(version.Must(version.NewVersion("v1.8.0-rc1"))), + }, + ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){ + "framework": providerserver.NewProtocol6WithError(New()), + }, + Steps: []resource.TestStep{ + { + Config: ` + output "test" { + value = provider::framework::dynamic_variadic(true, "string", 1234.5) + }`, + ConfigStateChecks: []statecheck.StateCheck{ + cornertesting.ExpectOutputType( + "test", + cty.Tuple( + []cty.Type{ + cty.Bool, + cty.String, + cty.Number, + }, + ), + ), + statecheck.ExpectKnownOutputValue("test", + knownvalue.TupleExact( + []knownvalue.Check{ + knownvalue.Bool(true), + knownvalue.StringExact("string"), + knownvalue.NumberExact(big.NewFloat(1234.5)), + }, + ), + ), + }, + }, + }, + }) +} func TestDynamicVariadicFunction_null(t *testing.T) { resource.UnitTest(t, resource.TestCase{ @@ -268,8 +292,15 @@ func TestDynamicVariadicFunction_unknown(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ + cornertesting.ExpectOutputType("test", + cty.Tuple( + []cty.Type{ + cty.String, + }, + ), + ), statecheck.ExpectKnownOutputValue("test", - knownvalue.ListExact( + knownvalue.TupleExact( []knownvalue.Check{ knownvalue.StringExact("test-value"), }, diff --git a/internal/framework6provider/schema_resource_test.go b/internal/framework6provider/schema_resource_test.go index b134036..30eac76 100644 --- a/internal/framework6provider/schema_resource_test.go +++ b/internal/framework6provider/schema_resource_test.go @@ -188,8 +188,7 @@ func TestSchemaResource_DynamicAttribute(t *testing.T) { "attribute_one": knownvalue.StringExact("value1"), "attribute_two": knownvalue.Bool(false), "attribute_three": knownvalue.NumberExact(big.NewFloat(1234.5)), - // ListExact can be used despite the underlying type being a tuple[bool, number] - "attribute_four": knownvalue.ListExact( + "attribute_four": knownvalue.TupleExact( []knownvalue.Check{ knownvalue.Bool(true), knownvalue.NumberExact(big.NewFloat(1234.5)),