Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FR and/or Doc: support for variadic parameters in unit testing and/or updates to corresponding documentation #1088

Open
mschuchard opened this issue Jan 23, 2025 · 1 comment
Labels
documentation Improvements or additions to documentation

Comments

@mschuchard
Copy link

Version: 1.11.0

At the moment I have a simple function with a variadic parameter where the parameter value retrieval occurs according to documentation:

VariadicParameter: function.Int32Parameter{
	Name:        "number_of_characters",
	Description: "Optional: The number of terminating characters at the end of the string to return (default: 1). This must be fewer than the number of characters in the input string.",
},
...
var numCharsVar []int32

resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &inputString, &numCharsVar))

During unit testing omitting the variadic parameter succeeds completely as expected:

"optional-param-absent": {
	request: function.RunRequest{
		Arguments: function.NewArgumentsData([]attr.Value{types.StringValue("hello"), types.Int32Null()}),
	},
	expected: function.RunResponse{
		Result: function.NewResultData(types.StringValue("o")),
	},
},

but specifying a value errors:

"three-terminating-chars": {
	request: function.RunRequest{
		Arguments: function.NewArgumentsData([]attr.Value{types.StringValue("hello"), types.Int32Value(3)}),
	},
	expected: function.RunResponse{
		Result: function.NewResultData(types.StringValue("llo")),
	},
},

actual value: Value Conversion Error: An unexpected error was encountered trying to convert tftypes.Value into []int32. This is always an error in the provider. Please report the following to the provider developer:
can't unmarshal tftypes.Number into *[]tftypes.Value expected []tftypes.Value

Ok so even though types.Int32Null() is valid in the function signature for the first unit test request, and it would also be a tuple tftype in the actual Terraform config, the expectation here in the unit testing framework is for the variadic parameters to be capable of marshalling to a slice?
Well the function.NewArgumentsData signature only accepts a single slice of attr.Value, and the second argument cannot be []types.Int32{types.Int32Value(3)} because the interface does not implement what is required for the attr.Value type, and so then is the variadic parameter argument supposed to be an enumerable tftype i.e. set or list?

So I am kind of at a coin flip between whether this is unsupported or undocumented.

Corollary: complex type return testing for e.g. tuples is supported although undocumented, and I did miraculously figure it out via:

"normal": {
	request: function.RunRequest{
		Arguments: function.NewArgumentsData([]attr.Value{types.StringValue("foobarbaz"), types.StringValue("bar")}),
	},
	expected: function.RunResponse{
		Result: function.NewResultData(types.TupleValueMust(
			[]attr.Type{types.StringType, types.StringType, types.BoolType},
			[]attr.Value{types.StringValue("foo"), types.StringValue("baz"), types.BoolValue(true)})),
	},
},

but this would also be benficial to add to documentation since e.g. currently in the AWS provider there is a function with an object tftype return and a "TODO: figure out how to do this" which implies both a documentation gap if they cannot figure it out, and also that probably some element of luck was involved with me actually figuring it out.

Thank you.

@mschuchard mschuchard added the documentation Improvements or additions to documentation label Jan 23, 2025
@austinvalle
Copy link
Member

Hey there @mschuchard 👋🏻 , I think our Framework documentation could be updated to give more details on unit testing functions. I'm going to transfer this issue over to terraform-plugin-framework 👍🏻

Confirming what you mentioned, variadic parameters are a little awkward to unit test as they are represented by a types.Tuple under the scenes (tuple is being used instead of a list to allow dynamic parameters of different types), which our reflection logic in req.Arguments.Get actually supports reflecting a tuple into a slice of a single type, as long as the tuple itself contains elements of a single type. We have some documentation about retrieving data for variadic parameters, but no docs about setting up unit tests for it.

If you wanted your unit test to match exactly how the data will come from Terraform to your function, you'd want something like:

"three-terminating-chars": {
    request: function.RunRequest{
        Arguments: function.NewArgumentsData(
            []attr.Value{
                types.StringValue("hello"),
                types.TupleValueMust(
                    []attr.Type{
                        types.Int32,
                    },
                    []attr.Value{
                        types.Int32Value(3),
                    },
                ),
            },
        ),
    },
    expected: function.RunResponse{
        Result: function.NewResultData(types.StringValue("llo")),
    },
},

As for the types.Int32Null() successfully reflecting into a []int32, I think that's just because our underlying reflection logic supports that (null anything to a slice). If you actually executed your logic, the underlying attr.Value should always be a tuple like above.

@austinvalle austinvalle transferred this issue from hashicorp/terraform-plugin-testing Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants