add VariableAssignment struct that help describe an input var assignment

This commit is contained in:
Adrien Delorme 2020-11-02 11:49:40 +01:00
parent 8de2f40a07
commit 6911495fc4
7 changed files with 335 additions and 205 deletions

View File

@ -69,25 +69,7 @@ func testParse(t *testing.T, tests []parseTest) {
if tt.parseWantDiagHasErrors != gotDiags.HasErrors() {
t.Fatalf("Parser.parse() unexpected diagnostics HasErrors. %s", gotDiags)
}
if diff := cmp.Diff(tt.parseWantCfg, gotCfg,
cmpopts.IgnoreUnexported(
PackerConfig{},
cty.Value{},
cty.Type{},
Variable{},
SourceBlock{},
ProvisionerBlock{},
PostProcessorBlock{},
),
cmpopts.IgnoreFields(PackerConfig{},
"Cwd", // Cwd will change for every computer
),
cmpopts.IgnoreTypes(HCL2Ref{}),
cmpopts.IgnoreTypes([]*LocalBlock{}),
cmpopts.IgnoreTypes([]hcl.Range{}),
cmpopts.IgnoreTypes(hcl.Range{}),
cmpopts.IgnoreInterfaces(struct{ hcl.Expression }{}),
cmpopts.IgnoreInterfaces(struct{ hcl.Body }{}),
if diff := cmp.Diff(tt.parseWantCfg, gotCfg, cmpOpts...,
); diff != "" {
t.Fatalf("Parser.parse() wrong packer config. %s", diff)
}
@ -96,11 +78,8 @@ func testParse(t *testing.T, tests []parseTest) {
gotInputVar := gotCfg.InputVariables
for name, value := range tt.parseWantCfg.InputVariables {
if variable, ok := gotInputVar[name]; ok {
if diff := cmp.Diff(variable.DefaultValue.GoString(), value.DefaultValue.GoString()); diff != "" {
t.Fatalf("Parser.parse(): unexpected default value for %s: %s", name, diff)
}
if diff := cmp.Diff(variable.VarfileValue.GoString(), value.VarfileValue.GoString()); diff != "" {
t.Fatalf("Parser.parse(): varfile value differs for %s: %s", name, diff)
if diff := cmp.Diff(variable, value, cmpOpts...); diff != "" {
t.Fatalf("Parser.parse(): unexpected variable values %s: %s", name, diff)
}
} else {
t.Fatalf("Parser.parse() missing input variable. %s", name)
@ -110,8 +89,8 @@ func testParse(t *testing.T, tests []parseTest) {
gotLocalVar := gotCfg.LocalVariables
for name, value := range tt.parseWantCfg.LocalVariables {
if variable, ok := gotLocalVar[name]; ok {
if variable.DefaultValue.GoString() != value.DefaultValue.GoString() {
t.Fatalf("Parser.parse() local variable %s expected '%s' but was '%s'", name, value.DefaultValue.GoString(), variable.DefaultValue.GoString())
if diff := cmp.Diff(variable, value, cmpOpts...); diff != "" {
t.Fatalf("Parser.parse(): unexpected variable values %s: %s", name, diff)
}
} else {
t.Fatalf("Parser.parse() missing local variable. %s", name)
@ -127,18 +106,7 @@ func testParse(t *testing.T, tests []parseTest) {
if tt.getBuildsWantDiags == (gotDiags == nil) {
t.Fatalf("Parser.getBuilds() unexpected diagnostics. %s", gotDiags)
}
if diff := cmp.Diff(tt.getBuildsWantBuilds, gotBuilds,
cmpopts.IgnoreUnexported(
cty.Value{},
cty.Type{},
packer.CoreBuild{},
packer.CoreBuildProvisioner{},
packer.CoreBuildPostProcessor{},
null.Builder{},
HCL2Provisioner{},
HCL2PostProcessor{},
),
); diff != "" {
if diff := cmp.Diff(tt.getBuildsWantBuilds, gotBuilds, cmpOpts...); diff != "" {
t.Fatalf("Parser.getBuilds() wrong packer builds. %s", diff)
}
})
@ -250,3 +218,34 @@ var (
},
}
)
var cmpOpts = []cmp.Option{
cmpopts.IgnoreUnexported(
PackerConfig{},
cty.Value{},
cty.Type{},
Variable{},
SourceBlock{},
ProvisionerBlock{},
PostProcessorBlock{},
packer.CoreBuild{},
HCL2Provisioner{},
HCL2PostProcessor{},
packer.CoreBuildPostProcessor{},
packer.CoreBuildProvisioner{},
packer.CoreBuildPostProcessor{},
null.Builder{},
),
cmpopts.IgnoreFields(PackerConfig{},
"Cwd", // Cwd will change for every os type
),
cmpopts.IgnoreFields(VariableAssignment{},
"Expr", // its an interface
),
cmpopts.IgnoreTypes(HCL2Ref{}),
cmpopts.IgnoreTypes([]*LocalBlock{}),
cmpopts.IgnoreTypes([]hcl.Range{}),
cmpopts.IgnoreTypes(hcl.Range{}),
cmpopts.IgnoreInterfaces(struct{ hcl.Expression }{}),
cmpopts.IgnoreInterfaces(struct{ hcl.Body }{}),
}

View File

@ -0,0 +1,17 @@
variable "image_metadata" {
default = {
key: "value",
something: {
foo: "bar",
}
}
validation {
condition = length(var.image_metadata.key) > 4
error_message = "The image_metadata.key field must be more than 4 runes."
}
validation {
condition = substr(var.image_metadata.something.foo, 0, 3) == "bar"
error_message = "The image_metadata.something.foo field must start with \"bar\"."
}
}

View File

@ -0,0 +1,7 @@
image_metadata = {
key: "value",
something: {
foo: "woo",
}
}

View File

@ -210,9 +210,13 @@ func (c *PackerConfig) evaluateLocalVariable(local *LocalBlock) hcl.Diagnostics
return diags
}
c.LocalVariables[local.Name] = &Variable{
Name: local.Name,
DefaultValue: value,
Type: value.Type(),
Name: local.Name,
Values: []VariableAssignment{{
Value: value,
Expr: local.Expr,
From: "default",
}},
Type: value.Type(),
}
return diags

View File

@ -25,51 +25,58 @@ func TestParser_complete(t *testing.T) {
Basedir: "testdata/complete",
InputVariables: Variables{
"foo": &Variable{
Name: "foo",
DefaultValue: cty.StringVal("value"),
Name: "foo",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("value")}},
},
"image_id": &Variable{
Name: "image_id",
DefaultValue: cty.StringVal("image-id-default"),
Name: "image_id",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("image-id-default")}},
},
"port": &Variable{
Name: "port",
DefaultValue: cty.NumberIntVal(42),
Name: "port",
Values: []VariableAssignment{{From: "default", Value: cty.NumberIntVal(42)}},
},
"availability_zone_names": &Variable{
Name: "availability_zone_names",
DefaultValue: cty.ListVal([]cty.Value{
cty.StringVal("A"),
cty.StringVal("B"),
cty.StringVal("C"),
}),
Values: []VariableAssignment{{
From: "default",
Value: cty.ListVal([]cty.Value{
cty.StringVal("A"),
cty.StringVal("B"),
cty.StringVal("C"),
}),
}},
},
},
LocalVariables: Variables{
"feefoo": &Variable{
Name: "feefoo",
DefaultValue: cty.StringVal("value_image-id-default"),
Name: "feefoo",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("value_image-id-default")}},
},
"standard_tags": &Variable{
Name: "standard_tags",
DefaultValue: cty.ObjectVal(map[string]cty.Value{
"Component": cty.StringVal("user-service"),
"Environment": cty.StringVal("production"),
}),
Values: []VariableAssignment{{From: "default",
Value: cty.ObjectVal(map[string]cty.Value{
"Component": cty.StringVal("user-service"),
"Environment": cty.StringVal("production"),
}),
}},
},
"abc_map": &Variable{
Name: "abc_map",
DefaultValue: cty.TupleVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("a"),
Values: []VariableAssignment{{From: "default",
Value: cty.TupleVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("a"),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("b"),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("c"),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("b"),
}),
cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("c"),
}),
}),
}},
},
},
Sources: map[SourceRef]SourceBlock{

View File

@ -26,15 +26,26 @@ type LocalBlock struct {
Expr hcl.Expression
}
// VariableAssignment represents a way a variable was set: the expression
// setting it and the value of that expression. It helps pinpoint were
// something was set in diagnostics.
type VariableAssignment struct {
// From tells were it was taken from, command/varfile/env/default
From string
Value cty.Value
Expr hcl.Expression
}
type Variable struct {
// CmdValue, VarfileValue, EnvValue, DefaultValue are possible values of
// the variable; The first value set from these will be the one used. If
// none is set; an error will be returned if a user tries to use the
// Variable.
CmdValue cty.Value
VarfileValue cty.Value
EnvValue cty.Value
DefaultValue cty.Value
// Values contains possible values for the variable; The last value set
// from these will be the one used. If none is set; an error will be
// returned by Value().
Values []VariableAssignment
// Validations contains all variables validation rules to be applied to the
// used value. Only the used value - the last value from Values - is
// validated.
Validations []*VariableValidation
// Cty Type of the variable. If the default value or a collected value is
// not of this type nor can be converted to this type an error diagnostic
@ -53,25 +64,23 @@ type Variable struct {
// the variable from the output stream. By replacing the text.
Sensitive bool
Validations []*VariableValidation
Range hcl.Range
}
func (v *Variable) GoString() string {
return fmt.Sprintf("{Type:%s,CmdValue:%s,VarfileValue:%s,EnvValue:%s,DefaultValue:%s}",
v.Type.GoString(),
PrintableCtyValue(v.CmdValue),
PrintableCtyValue(v.VarfileValue),
PrintableCtyValue(v.EnvValue),
PrintableCtyValue(v.DefaultValue),
)
b := &strings.Builder{}
fmt.Fprintf(b, "{type:%s", v.Type.GoString())
for _, vv := range v.Values {
fmt.Fprintf(b, ",%s:%s", vv.From, vv.Value)
}
fmt.Fprintf(b, "}")
return b.String()
}
// validateValue ensures that all of the configured custom validations for a
// variable value are passing.
//
func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
func (v *Variable) validateValue(val VariableAssignment) (diags hcl.Diagnostics) {
if len(v.Validations) == 0 {
log.Printf("[TRACE] validateValue: not active for %s, so skipping", v.Name)
return nil
@ -80,7 +89,7 @@ func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
hclCtx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.ObjectVal(map[string]cty.Value{
v.Name: val,
v.Name: val.Value,
}),
},
Functions: Functions(""),
@ -88,7 +97,6 @@ func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
for _, validation := range v.Validations {
const errInvalidCondition = "Invalid variable validation result"
const errInvalidValue = "Invalid value for variable"
result, moreDiags := validation.Condition.Value(hclCtx)
diags = append(diags, moreDiags...)
@ -125,11 +133,15 @@ func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
}
if result.False() {
subj := validation.DeclRange.Ptr()
if val.Expr != nil {
subj = val.Expr.Range().Ptr()
}
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: errInvalidValue,
Summary: fmt.Sprintf("Invalid value for %s variable", val.From),
Detail: fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", validation.ErrorMessage, validation.DeclRange.String()),
Subject: validation.DeclRange.Ptr(),
Subject: subj,
})
}
}
@ -137,26 +149,20 @@ func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
return diags
}
// Value returns the last found value from the list of variable settings.
func (v *Variable) Value() (cty.Value, hcl.Diagnostics) {
for _, value := range []cty.Value{
v.CmdValue,
v.VarfileValue,
v.EnvValue,
v.DefaultValue,
} {
if value != cty.NilVal {
return value, v.validateValue(value)
}
if len(v.Values) == 0 {
return cty.UnknownVal(v.Type), hcl.Diagnostics{&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Unset variable %q", v.Name),
Detail: "A used variable must be set or have a default value; see " +
"https://packer.io/docs/configuration/from-1.5/syntax for " +
"details.",
Context: v.Range.Ptr(),
}}
}
return cty.UnknownVal(v.Type), hcl.Diagnostics{&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Unset variable %q", v.Name),
Detail: "A used variable must be set or have a default value; see " +
"https://packer.io/docs/configuration/from-1.5/syntax for " +
"details.",
Context: v.Range.Ptr(),
}}
val := v.Values[len(v.Values)-1]
return val.Value, v.validateValue(v.Values[len(v.Values)-1])
}
type Variables map[string]*Variable
@ -205,10 +211,14 @@ func (variables *Variables) decodeVariable(key string, attr *hcl.Attribute, ectx
}
(*variables)[key] = &Variable{
Name: key,
DefaultValue: value,
Type: value.Type(),
Range: attr.Range,
Name: key,
Values: []VariableAssignment{{
From: "default",
Value: value,
Expr: attr.Expr,
}},
Type: value.Type(),
Range: attr.Range,
}
return diags
@ -310,12 +320,16 @@ func (variables *Variables) decodeVariableBlock(block *hcl.Block, ectx *hcl.Eval
}
}
v.DefaultValue = defaultValue
v.Values = append(v.Values, VariableAssignment{
From: "default",
Value: defaultValue,
Expr: def.Expr,
})
// It's possible no type attribute was assigned so lets make sure we
// have a valid type otherwise there could be issues parsing the value.
if v.Type == cty.NilType {
v.Type = v.DefaultValue.Type()
v.Type = defaultValue.Type()
}
}
@ -532,7 +546,11 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
val = cty.DynamicVal
}
}
variable.EnvValue = val
variable.Values = append(variable.Values, VariableAssignment{
From: "env",
Value: val,
Expr: expr,
})
}
// files will contain files found in the folder then files passed as
@ -616,7 +634,11 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
}
}
variable.VarfileValue = val
variable.Values = append(variable.Values, VariableAssignment{
From: "varfile",
Value: val,
Expr: attr.Expr,
})
}
}
@ -660,7 +682,11 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
}
}
variable.CmdValue = val
variable.Values = append(variable.Values, VariableAssignment{
From: "cmd",
Value: val,
Expr: expr,
})
}
return diags

View File

@ -25,47 +25,59 @@ func TestParse_variables(t *testing.T) {
Basedir: filepath.Join("testdata", "variables"),
InputVariables: Variables{
"image_name": &Variable{
Name: "image_name",
DefaultValue: cty.StringVal("foo-image-{{user `my_secret`}}"),
Name: "image_name",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo-image-{{user `my_secret`}}")}},
},
"key": &Variable{
Name: "key",
DefaultValue: cty.StringVal("value"),
Name: "key",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("value")}},
},
"my_secret": &Variable{
Name: "my_secret",
DefaultValue: cty.StringVal("foo"),
Name: "my_secret",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
"image_id": &Variable{
Name: "image_id",
DefaultValue: cty.StringVal("image-id-default"),
Name: "image_id",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("image-id-default")}},
},
"port": &Variable{
Name: "port",
DefaultValue: cty.NumberIntVal(42),
Name: "port",
Values: []VariableAssignment{{From: "default", Value: cty.NumberIntVal(42)}},
},
"availability_zone_names": &Variable{
Name: "availability_zone_names",
DefaultValue: cty.ListVal([]cty.Value{
cty.StringVal("us-west-1a"),
}),
Values: []VariableAssignment{{
From: "default",
Value: cty.ListVal([]cty.Value{
cty.StringVal("us-west-1a"),
}),
}},
Description: fmt.Sprintln("Describing is awesome ;D"),
},
"super_secret_password": &Variable{
Name: "super_secret_password",
Sensitive: true,
DefaultValue: cty.NullVal(cty.String),
Description: fmt.Sprintln("Handle with care plz"),
Name: "super_secret_password",
Sensitive: true,
Values: []VariableAssignment{{
From: "default",
Value: cty.NullVal(cty.String),
}},
Description: fmt.Sprintln("Handle with care plz"),
},
},
LocalVariables: Variables{
"owner": &Variable{
Name: "owner",
DefaultValue: cty.StringVal("Community Team"),
Name: "owner",
Values: []VariableAssignment{{
From: "default",
Value: cty.StringVal("Community Team"),
}},
},
"service_name": &Variable{
Name: "service_name",
DefaultValue: cty.StringVal("forum"),
Name: "service_name",
Values: []VariableAssignment{{
From: "default",
Value: cty.StringVal("forum"),
}},
},
},
},
@ -81,6 +93,10 @@ func TestParse_variables(t *testing.T) {
InputVariables: Variables{
"boolean_value": &Variable{
Name: "boolean_value",
Values: []VariableAssignment{{
From: "default",
Value: cty.BoolVal(false),
}},
},
},
},
@ -96,6 +112,10 @@ func TestParse_variables(t *testing.T) {
InputVariables: Variables{
"boolean_value": &Variable{
Name: "boolean_value",
Values: []VariableAssignment{{
From: "default",
Value: cty.BoolVal(false),
}},
},
},
},
@ -111,6 +131,10 @@ func TestParse_variables(t *testing.T) {
InputVariables: Variables{
"broken_type": &Variable{
Name: "broken_type",
Values: []VariableAssignment{{
From: "default",
Value: cty.UnknownVal(cty.DynamicPseudoType),
}},
},
},
},
@ -126,8 +150,8 @@ func TestParse_variables(t *testing.T) {
Basedir: filepath.Join("testdata", "variables"),
InputVariables: Variables{
"broken_variable": &Variable{
Name: "broken_variable",
DefaultValue: cty.BoolVal(true),
Name: "broken_variable",
Values: []VariableAssignment{{From: "default", Value: cty.BoolVal(true)}},
},
},
},
@ -196,34 +220,37 @@ func TestParse_variables(t *testing.T) {
Basedir: "testdata/variables/complicated",
InputVariables: Variables{
"name_prefix": &Variable{
Name: "name_prefix",
DefaultValue: cty.StringVal("foo"),
Name: "name_prefix",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
},
LocalVariables: Variables{
"name_prefix": &Variable{
Name: "name_prefix",
DefaultValue: cty.StringVal("foo"),
Name: "name_prefix",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
"foo": &Variable{
Name: "foo",
DefaultValue: cty.StringVal("foo"),
Name: "foo",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
"bar": &Variable{
Name: "bar",
DefaultValue: cty.StringVal("foo"),
Name: "bar",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
"for_var": &Variable{
Name: "for_var",
DefaultValue: cty.StringVal("foo"),
Name: "for_var",
Values: []VariableAssignment{{From: "default", Value: cty.StringVal("foo")}},
},
"bar_var": &Variable{
Name: "bar_var",
DefaultValue: cty.TupleVal([]cty.Value{
cty.StringVal("foo"),
cty.StringVal("foo"),
cty.StringVal("foo"),
}),
Values: []VariableAssignment{{
From: "default",
Value: cty.TupleVal([]cty.Value{
cty.StringVal("foo"),
cty.StringVal("foo"),
cty.StringVal("foo"),
}),
}},
},
},
},
@ -250,9 +277,11 @@ func TestParse_variables(t *testing.T) {
Basedir: filepath.Join("testdata", "variables"),
InputVariables: Variables{
"foo": &Variable{
DefaultValue: cty.StringVal("bar"),
Name: "foo",
VarfileValue: cty.StringVal("wee"),
Name: "foo",
Values: []VariableAssignment{
VariableAssignment{"default", cty.StringVal("bar"), nil},
VariableAssignment{"varfile", cty.StringVal("wee"), nil},
},
},
},
},
@ -279,14 +308,14 @@ func TestParse_variables(t *testing.T) {
Basedir: filepath.Join("testdata", "variables"),
InputVariables: Variables{
"max_retries": &Variable{
Name: "max_retries",
DefaultValue: cty.StringVal("1"),
Type: cty.String,
Name: "max_retries",
Values: []VariableAssignment{{"default", cty.StringVal("1"), nil}},
Type: cty.String,
},
"max_retries_int": &Variable{
Name: "max_retries_int",
DefaultValue: cty.NumberIntVal(1),
Type: cty.Number,
Name: "max_retries_int",
Values: []VariableAssignment{{"default", cty.NumberIntVal(1), nil}},
Type: cty.Number,
},
},
Sources: map[SourceRef]SourceBlock{
@ -365,8 +394,10 @@ func TestParse_variables(t *testing.T) {
Basedir: filepath.Join("testdata", "variables", "validation"),
InputVariables: Variables{
"image_id": &Variable{
DefaultValue: cty.StringVal("ami-something-something"),
Name: "image_id",
Values: []VariableAssignment{
{"default", cty.StringVal("ami-something-something"), nil},
},
Name: "image_id",
Validations: []*VariableValidation{
&VariableValidation{
ErrorMessage: `The image_id value must be a valid AMI id, starting with "ami-".`,
@ -379,6 +410,28 @@ func TestParse_variables(t *testing.T) {
[]packer.Build{},
false,
},
{"valid validation block - invalid default",
defaultParser,
parseTestArgs{"testdata/variables/validation/invalid_default.pkr.hcl", nil, nil},
&PackerConfig{
Basedir: filepath.Join("testdata", "variables", "validation"),
InputVariables: Variables{
"image_id": &Variable{
Values: []VariableAssignment{{"default", cty.StringVal("ami-something-something"), nil}},
Name: "image_id",
Validations: []*VariableValidation{
&VariableValidation{
ErrorMessage: `The image_id value must be a valid AMI id, starting with "ami-".`,
},
},
},
},
},
true, true,
nil,
false,
},
}
testParse(t, tests)
}
@ -402,8 +455,10 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "string",
variables: Variables{"used_string": &Variable{
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
Values: []VariableAssignment{
{"default", cty.StringVal("default_value"), nil},
},
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_used_string=env_value`},
@ -420,11 +475,14 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
CmdValue: cty.StringVal("cmd_value"),
VarfileValue: cty.StringVal("varfile_value"),
EnvValue: cty.StringVal("env_value"),
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
Values: []VariableAssignment{
{"default", cty.StringVal(`"default_value"`), nil},
{"env", cty.StringVal(`"env_value"`), nil},
{"varfile", cty.StringVal(`"xy"`), nil},
{"varfile", cty.StringVal(`"varfile_value"`), nil},
{"cmd", cty.StringVal(`"cmd_value"`), nil},
},
},
},
wantValues: map[string]cty.Value{
@ -434,8 +492,10 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "quoted string",
variables: Variables{"quoted_string": &Variable{
DefaultValue: cty.StringVal(`"default_value"`),
Type: cty.String,
Values: []VariableAssignment{
{"default", cty.StringVal(`"default_value"`), nil},
},
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_quoted_string="env_value"`},
@ -452,11 +512,14 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"quoted_string": &Variable{
Type: cty.String,
CmdValue: cty.StringVal(`"cmd_value"`),
VarfileValue: cty.StringVal(`"varfile_value"`),
EnvValue: cty.StringVal(`"env_value"`),
DefaultValue: cty.StringVal(`"default_value"`),
Type: cty.String,
Values: []VariableAssignment{
{"default", cty.StringVal(`"default_value"`), nil},
{"env", cty.StringVal(`"env_value"`), nil},
{"varfile", cty.StringVal(`"xy"`), nil},
{"varfile", cty.StringVal(`"varfile_value"`), nil},
{"cmd", cty.StringVal(`"cmd_value"`), nil},
},
},
},
wantValues: map[string]cty.Value{
@ -466,8 +529,10 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "array of strings",
variables: Variables{"used_strings": &Variable{
DefaultValue: stringListVal("default_value_1"),
Type: cty.List(cty.String),
Values: []VariableAssignment{
{"default", stringListVal("default_value_1"), nil},
},
Type: cty.List(cty.String),
}},
args: args{
env: []string{`PKR_VAR_used_strings=["env_value_1", "env_value_2"]`},
@ -484,11 +549,14 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"used_strings": &Variable{
Type: cty.List(cty.String),
CmdValue: stringListVal("cmd_value_1"),
VarfileValue: stringListVal("varfile_value_1"),
EnvValue: stringListVal("env_value_1", "env_value_2"),
DefaultValue: stringListVal("default_value_1"),
Type: cty.List(cty.String),
Values: []VariableAssignment{
{"default", stringListVal("default_value_1"), nil},
{"env", stringListVal("env_value_1", "env_value_2"), nil},
{"varfile", stringListVal("xy"), nil},
{"varfile", stringListVal("varfile_value_1"), nil},
{"cmd", stringListVal("cmd_value_1"), nil},
},
},
},
wantValues: map[string]cty.Value{
@ -498,8 +566,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "bool",
variables: Variables{"enabled": &Variable{
DefaultValue: cty.False,
Type: cty.Bool,
Values: []VariableAssignment{{"default", cty.False, nil}},
Type: cty.Bool,
}},
args: args{
env: []string{`PKR_VAR_enabled=true`},
@ -515,11 +583,13 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"enabled": &Variable{
Type: cty.Bool,
CmdValue: cty.True,
VarfileValue: cty.False,
EnvValue: cty.True,
DefaultValue: cty.False,
Type: cty.Bool,
Values: []VariableAssignment{
{"default", cty.False, nil},
{"env", cty.True, nil},
{"varfile", cty.False, nil},
{"cmd", cty.True, nil},
},
},
},
wantValues: map[string]cty.Value{
@ -529,8 +599,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
{name: "invalid env var",
variables: Variables{"used_string": &Variable{
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
Values: []VariableAssignment{{"default", cty.StringVal("default_value"), nil}},
Type: cty.String,
}},
args: args{
env: []string{`PKR_VAR_used_string`},
@ -540,8 +610,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiags: false,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.String,
DefaultValue: cty.StringVal("default_value"),
Type: cty.String,
Values: []VariableAssignment{{"default", cty.StringVal("default_value"), nil}},
},
},
wantValues: map[string]cty.Value{
@ -620,8 +690,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.List(cty.String),
EnvValue: cty.DynamicVal,
Type: cty.List(cty.String),
Values: []VariableAssignment{{"env", cty.DynamicVal, nil}},
},
},
wantValues: map[string]cty.Value{
@ -644,8 +714,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.Bool,
VarfileValue: cty.DynamicVal,
Type: cty.Bool,
Values: []VariableAssignment{{"varfile", cty.DynamicVal, nil}},
},
},
wantValues: map[string]cty.Value{
@ -670,8 +740,8 @@ func TestVariables_collectVariableValues(t *testing.T) {
wantDiagsHasError: true,
wantVariables: Variables{
"used_string": &Variable{
Type: cty.Bool,
CmdValue: cty.DynamicVal,
Type: cty.Bool,
Values: []VariableAssignment{{"cmd", cty.DynamicVal, nil}},
},
},
wantValues: map[string]cty.Value{
@ -714,7 +784,7 @@ func TestVariables_collectVariableValues(t *testing.T) {
if tt.wantDiagsHasError != gotDiags.HasErrors() {
t.Fatalf("Variables.collectVariableValues() unexpected diagnostics HasErrors. %s", gotDiags)
}
if diff := cmp.Diff(fmt.Sprintf("%#v", tt.wantVariables), fmt.Sprintf("%#v", tt.variables)); diff != "" {
if diff := cmp.Diff(tt.wantVariables, tt.variables, cmpOpts...); diff != "" {
t.Fatalf("didn't get expected variables: %s", diff)
}
values := map[string]cty.Value{}