| package terraform |
| |
| import ( |
| "testing" |
| |
| "github.com/hashicorp/terraform/internal/configs" |
| "github.com/zclconf/go-cty/cty" |
| ) |
| |
| func TestCheckInputVariables(t *testing.T) { |
| c := testModule(t, "input-variables") |
| |
| t.Run("No variables set", func(t *testing.T) { |
| // No variables set |
| diags := checkInputVariables(c.Module.Variables, nil) |
| if !diags.HasErrors() { |
| t.Fatal("check succeeded, but want errors") |
| } |
| |
| // Required variables set, optional variables unset |
| // This is still an error at this layer, since it's the caller's |
| // responsibility to have already merged in any default values. |
| diags = checkInputVariables(c.Module.Variables, InputValues{ |
| "foo": &InputValue{ |
| Value: cty.StringVal("bar"), |
| SourceType: ValueFromCLIArg, |
| }, |
| }) |
| if !diags.HasErrors() { |
| t.Fatal("check succeeded, but want errors") |
| } |
| }) |
| |
| t.Run("All variables set", func(t *testing.T) { |
| diags := checkInputVariables(c.Module.Variables, InputValues{ |
| "foo": &InputValue{ |
| Value: cty.StringVal("bar"), |
| SourceType: ValueFromCLIArg, |
| }, |
| "bar": &InputValue{ |
| Value: cty.StringVal("baz"), |
| SourceType: ValueFromCLIArg, |
| }, |
| "map": &InputValue{ |
| Value: cty.StringVal("baz"), // okay because config has no type constraint |
| SourceType: ValueFromCLIArg, |
| }, |
| "object_map": &InputValue{ |
| Value: cty.MapVal(map[string]cty.Value{ |
| "uno": cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("baz"), |
| "bar": cty.NumberIntVal(2), // type = any |
| }), |
| "dos": cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("bat"), |
| "bar": cty.NumberIntVal(99), // type = any |
| }), |
| }), |
| SourceType: ValueFromCLIArg, |
| }, |
| "object_list": &InputValue{ |
| Value: cty.ListVal([]cty.Value{ |
| cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("baz"), |
| "bar": cty.NumberIntVal(2), // type = any |
| }), |
| cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("bang"), |
| "bar": cty.NumberIntVal(42), // type = any |
| }), |
| }), |
| SourceType: ValueFromCLIArg, |
| }, |
| }) |
| if diags.HasErrors() { |
| t.Fatalf("unexpected errors: %s", diags.Err()) |
| } |
| }) |
| |
| t.Run("Invalid Complex Types", func(t *testing.T) { |
| diags := checkInputVariables(c.Module.Variables, InputValues{ |
| "foo": &InputValue{ |
| Value: cty.StringVal("bar"), |
| SourceType: ValueFromCLIArg, |
| }, |
| "bar": &InputValue{ |
| Value: cty.StringVal("baz"), |
| SourceType: ValueFromCLIArg, |
| }, |
| "map": &InputValue{ |
| Value: cty.StringVal("baz"), // okay because config has no type constraint |
| SourceType: ValueFromCLIArg, |
| }, |
| "object_map": &InputValue{ |
| Value: cty.MapVal(map[string]cty.Value{ |
| "uno": cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("baz"), |
| "bar": cty.NumberIntVal(2), // type = any |
| }), |
| "dos": cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("bat"), |
| "bar": cty.NumberIntVal(99), // type = any |
| }), |
| }), |
| SourceType: ValueFromCLIArg, |
| }, |
| "object_list": &InputValue{ |
| Value: cty.TupleVal([]cty.Value{ |
| cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("baz"), |
| "bar": cty.NumberIntVal(2), // type = any |
| }), |
| cty.ObjectVal(map[string]cty.Value{ |
| "foo": cty.StringVal("bang"), |
| "bar": cty.StringVal("42"), // type = any, but mismatch with the first list item |
| }), |
| }), |
| SourceType: ValueFromCLIArg, |
| }, |
| }) |
| |
| if diags.HasErrors() { |
| t.Fatalf("unexpected errors: %s", diags.Err()) |
| } |
| }) |
| } |
| |
| // testInputValuesUnset is a helper for constructing InputValues values for |
| // situations where all of the root module variables are optional and a |
| // test case intends to just use those default values and not override them |
| // at all. |
| // |
| // In other words, this constructs an InputValues with one entry per given |
| // input variable declaration where all of them are declared as unset. |
| func testInputValuesUnset(decls map[string]*configs.Variable) InputValues { |
| if len(decls) == 0 { |
| return nil |
| } |
| |
| ret := make(InputValues, len(decls)) |
| for name := range decls { |
| ret[name] = &InputValue{ |
| Value: cty.NilVal, |
| SourceType: ValueFromUnknown, |
| } |
| } |
| return ret |
| } |