Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aaf1a17

Browse files
committed
chore: refactor validation while still keeping it mostly the same
Some validation changes: - Invalid options rejected (not in option set)
1 parent b6787b0 commit aaf1a17

File tree

3 files changed

+183
-168
lines changed

3 files changed

+183
-168
lines changed

provider/parameter.go

+112-97
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,25 @@ func parameterDataSource() *schema.Resource {
123123
if err != nil {
124124
return diag.Errorf("decode parameter: %s", err)
125125
}
126-
value := parameter.Default
126+
127+
var value *string
128+
if !rd.GetRawConfig().AsValueMap()["default"].IsNull() {
129+
value = &parameter.Default
130+
}
131+
127132
envValue, ok := os.LookupEnv(ParameterEnvironmentVariable(parameter.Name))
128133
if ok {
129-
value = envValue
134+
value = &envValue
135+
}
136+
137+
if value != nil {
138+
rd.Set("value", value)
139+
} else {
140+
// Maintaining backwards compatibility. The previous behavior was
141+
// to write back an empty string.
142+
// TODO: Should an empty string exist if no value is set?
143+
rd.Set("value", "")
130144
}
131-
rd.Set("value", value)
132145

133146
if !parameter.Mutable && parameter.Ephemeral {
134147
return diag.Errorf("parameter can't be immutable and ephemeral")
@@ -138,21 +151,6 @@ func parameterDataSource() *schema.Resource {
138151
return diag.Errorf("ephemeral parameter requires the default property")
139152
}
140153

141-
// Do ValidateFormType up front. If there is no error, update the
142-
// 'parameter.FormType' value to the new value. This is to handle default cases,
143-
// since the default logic is more advanced than the sdk provider schema
144-
// supports.
145-
//_, newFT, err := ValidateFormType(parameter.Type, len(parameter.Option), parameter.FormType)
146-
//if err == nil {
147-
// // If there is an error, parameter.Valid will catch it.
148-
// parameter.FormType = newFT
149-
//
150-
// // Set the form_type back in case the value was changed.
151-
// // Eg via a default. If a user does not specify, a default value
152-
// // is used and saved.
153-
// rd.Set("form_type", parameter.FormType)
154-
//}
155-
156154
diags := parameter.Valid(value)
157155
if diags.HasError() {
158156
return diags
@@ -399,12 +397,7 @@ func valueIsType(typ OptionType, value string) error {
399397
return nil
400398
}
401399

402-
func (v *Parameter) RelaxedValidation(value string) diag.Diagnostics {
403-
404-
return nil
405-
}
406-
407-
func (v *Parameter) Valid(value string) diag.Diagnostics {
400+
func (v *Parameter) Valid(value *string) diag.Diagnostics {
408401
var err error
409402
var optionType OptionType
410403

@@ -422,88 +415,125 @@ func (v *Parameter) Valid(value string) diag.Diagnostics {
422415
}
423416
}
424417

425-
optionNames := map[string]any{}
426-
optionValues := map[string]any{}
427-
if len(v.Option) > 0 {
428-
for _, option := range v.Option {
429-
_, exists := optionNames[option.Name]
430-
if exists {
431-
return diag.Diagnostics{{
432-
Severity: diag.Error,
433-
Summary: "Option names must be unique.",
434-
Detail: fmt.Sprintf("multiple options found with the same name %q", option.Name),
435-
},
436-
}
437-
}
438-
_, exists = optionValues[option.Value]
439-
if exists {
440-
return diag.Diagnostics{
441-
{
442-
Severity: diag.Error,
443-
Summary: "Option values must be unique.",
444-
Detail: fmt.Sprintf("multiple options found with the same value %q", option.Value),
445-
},
446-
}
447-
}
448-
err = valueIsType(optionType, option.Value)
449-
if err != nil {
450-
return diag.Diagnostics{
451-
{
452-
Severity: diag.Error,
453-
Summary: fmt.Sprintf("Option %q with value=%q is not of type %q", option.Name, option.Value, optionType),
454-
Detail: err.Error(),
455-
},
456-
}
457-
}
458-
optionValues[option.Value] = nil
459-
optionNames[option.Name] = nil
460-
461-
// TODO: Option values should also be validated.
462-
// v.validValue(option.Value, optionType, nil, cty.Path{})
463-
}
418+
optionValues, diags := v.ValidOptions(optionType)
419+
if diags.HasError() {
420+
return diags
464421
}
465422

466-
// Validate the default value
467-
if v.Default != "" {
468-
err := valueIsType(v.Type, v.Default)
423+
// TODO: The default value should also be validated
424+
//if v.Default != "" {
425+
// err := valueIsType(v.Type, v.Default)
426+
// if err != nil {
427+
// return diag.Diagnostics{
428+
// {
429+
// Severity: diag.Error,
430+
// Summary: fmt.Sprintf("Default value is not of type %q", v.Type),
431+
// Detail: err.Error(),
432+
// AttributePath: defaultValuePath,
433+
// },
434+
// }
435+
// }
436+
//
437+
// d := v.validValue(v.Default, optionType, optionValues, defaultValuePath)
438+
// if d.HasError() {
439+
// return d
440+
// }
441+
//}
442+
443+
// TODO: Move this into 'Parameter.validValue'. It exists as another check outside because
444+
// the current behavior is to always apply this validation, regardless if the param is set or not.
445+
// Other validations are only applied if the parameter is set.
446+
// This behavior should be standardized.
447+
if len(v.Validation) == 1 {
448+
empty := ""
449+
validVal := value
450+
if value == nil {
451+
validVal = &empty
452+
}
453+
validCheck := &v.Validation[0]
454+
err := validCheck.Valid(v.Type, *validVal)
469455
if err != nil {
470456
return diag.Diagnostics{
471457
{
472458
Severity: diag.Error,
473-
Summary: fmt.Sprintf("Default value is not of type %q", v.Type),
459+
Summary: fmt.Sprintf("Invalid parameter %s according to 'validation' block", strings.ToLower(v.Name)),
474460
Detail: err.Error(),
475-
AttributePath: defaultValuePath,
461+
AttributePath: cty.Path{},
476462
},
477463
}
478464
}
465+
}
479466

480-
d := v.validValue(v.Default, optionType, optionValues, defaultValuePath)
467+
// Value is only validated if it is set. If it is unset, validation
468+
// is skipped.
469+
if value != nil {
470+
d := v.validValue(*value, optionType, optionValues, cty.Path{})
481471
if d.HasError() {
482472
return d
483473
}
484-
}
485474

486-
// Value must always be validated
487-
d := v.validValue(value, optionType, optionValues, cty.Path{})
488-
if d.HasError() {
489-
return d
475+
err = valueIsType(v.Type, *value)
476+
if err != nil {
477+
return diag.Diagnostics{
478+
{
479+
Severity: diag.Error,
480+
Summary: fmt.Sprintf("Parameter value is not of type %q", v.Type),
481+
Detail: err.Error(),
482+
},
483+
}
484+
}
490485
}
491486

492-
err = valueIsType(v.Type, value)
493-
if err != nil {
494-
return diag.Diagnostics{
495-
{
487+
return nil
488+
}
489+
490+
func (v *Parameter) ValidOptions(optionType OptionType) (map[string]struct{}, diag.Diagnostics) {
491+
optionNames := map[string]struct{}{}
492+
optionValues := map[string]struct{}{}
493+
494+
var diags diag.Diagnostics
495+
for _, option := range v.Option {
496+
_, exists := optionNames[option.Name]
497+
if exists {
498+
return nil, diag.Diagnostics{{
496499
Severity: diag.Error,
497-
Summary: fmt.Sprintf("Parameter value is not of type %q", v.Type),
500+
Summary: "Option names must be unique.",
501+
Detail: fmt.Sprintf("multiple options found with the same name %q", option.Name),
502+
}}
503+
}
504+
505+
_, exists = optionValues[option.Value]
506+
if exists {
507+
return nil, diag.Diagnostics{{
508+
Severity: diag.Error,
509+
Summary: "Option values must be unique.",
510+
Detail: fmt.Sprintf("multiple options found with the same value %q", option.Value),
511+
}}
512+
}
513+
514+
err := valueIsType(optionType, option.Value)
515+
if err != nil {
516+
diags = append(diags, diag.Diagnostic{
517+
Severity: diag.Error,
518+
Summary: fmt.Sprintf("Option %q with value=%q is not of type %q", option.Name, option.Value, optionType),
498519
Detail: err.Error(),
499-
},
520+
})
521+
continue
500522
}
523+
optionValues[option.Value] = struct{}{}
524+
optionNames[option.Name] = struct{}{}
525+
526+
// TODO: Option values should also be validated.
527+
// v.validValue(option.Value, optionType, nil, cty.Path{})
501528
}
502529

503-
return nil
530+
if diags.HasError() {
531+
return nil, diags
532+
}
533+
return optionValues, nil
504534
}
505535

506-
func (v *Parameter) validValue(value string, optionType OptionType, optionValues map[string]any, path cty.Path) diag.Diagnostics {
536+
func (v *Parameter) validValue(value string, optionType OptionType, optionValues map[string]struct{}, path cty.Path) diag.Diagnostics {
507537
// name is used for constructing more precise error messages.
508538
name := "Value"
509539
if path.Equals(defaultValuePath) {
@@ -568,21 +598,6 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
568598
}
569599
}
570600

571-
if len(v.Validation) == 1 {
572-
validCheck := &v.Validation[0]
573-
err := validCheck.Valid(v.Type, value)
574-
if err != nil {
575-
return diag.Diagnostics{
576-
{
577-
Severity: diag.Error,
578-
Summary: fmt.Sprintf("Invalid parameter %s according to 'validation' block", strings.ToLower(name)),
579-
Detail: err.Error(),
580-
AttributePath: path,
581-
},
582-
}
583-
}
584-
}
585-
586601
return nil
587602
}
588603

provider/parameter_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ func TestParameterValidation(t *testing.T) {
835835
tc := tc
836836
t.Run(tc.Name, func(t *testing.T) {
837837
t.Parallel()
838-
diags := tc.Parameter.Valid(tc.Value)
838+
diags := tc.Parameter.Valid(&tc.Value)
839839
if tc.ExpectError != nil {
840840
require.True(t, diags.HasError())
841841
errMsg := fmt.Sprintf("%+v", diags[0]) // close enough

0 commit comments

Comments
 (0)