helper/schema: couple more tests around Computed (+ fix)

This commit is contained in:
Mitchell Hashimoto 2014-08-16 09:49:22 -07:00
parent 3a46d21527
commit 7bc0be4b81
4 changed files with 116 additions and 6 deletions

View File

@ -66,6 +66,10 @@ func (r *Resource) InternalValidate() error {
return fmt.Errorf("%s: Cannot be both Required and Computed", k) return fmt.Errorf("%s: Cannot be both Required and Computed", k)
} }
if len(v.ComputedWhen) > 0 && !v.Computed {
return fmt.Errorf("%s: ComputedWhen can only be set with Computed", k)
}
if v.Type == TypeList { if v.Type == TypeList {
if v.Elem == nil { if v.Elem == nil {
return fmt.Errorf("%s: Elem must be set for lists", k) return fmt.Errorf("%s: Elem must be set for lists", k)

View File

@ -94,6 +94,20 @@ func TestResourceInternalValidate(t *testing.T) {
}, },
true, true,
}, },
// Required but computed
{
&Resource{
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeInt,
Required: true,
ComputedWhen: []string{"foo"},
},
},
},
true,
},
} }
for i, tc := range cases { for i, tc := range cases {

View File

@ -30,9 +30,13 @@ type Schema struct {
Optional bool Optional bool
Required bool Required bool
// The fields below relate to diffs: if Computed is true, then the // The fields below relate to diffs.
// result of this value is computed (unless specified by config). //
// If ForceNew is true // If Computed is true, then the result of this value is computed
// (unless specified by config) on creation.
//
// If ForceNew is true, then a change in this resource necessitates
// the creation of a new resource.
Computed bool Computed bool
ForceNew bool ForceNew bool
@ -43,6 +47,11 @@ type Schema struct {
// the element type is just a simple value. If it is *Resource, the // the element type is just a simple value. If it is *Resource, the
// element type is a complex structure, potentially with its own lifecycle. // element type is a complex structure, potentially with its own lifecycle.
Elem interface{} Elem interface{}
// ComputedWhen is a set of queries on the configuration. Whenever any
// of these things is changed, it will require a recompute (this requires
// that Computed is set to true).
ComputedWhen []string
} }
func (s *Schema) finalizeDiff( func (s *Schema) finalizeDiff(
@ -51,9 +60,17 @@ func (s *Schema) finalizeDiff(
return d return d
} }
if s.Computed && d.New == "" { if s.Computed {
// Computed attribute without a new value set if d.Old != "" && d.New == "" {
d.NewComputed = true // This is a computed value with an old value set already,
// just let it go.
return nil
}
if d.New == "" {
// Computed attribute without a new value set
d.NewComputed = true
}
} }
if s.ForceNew { if s.ForceNew {
@ -95,6 +112,12 @@ func (m schemaMap) Diff(
} }
} }
for k, v := range result.Attributes {
if v == nil {
delete(result.Attributes, k)
}
}
if result.Empty() { if result.Empty() {
// If we don't have any diff elements, just return nil // If we don't have any diff elements, just return nil
return nil, nil return nil, nil

View File

@ -436,6 +436,75 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: true, Err: true,
}, },
/*
* ComputedWhen
*/
{
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Computed: true,
ComputedWhen: []string{"port"},
},
"port": &Schema{
Type: TypeInt,
Optional: true,
},
},
State: &terraform.ResourceState{
Attributes: map[string]string{
"availability_zone": "foo",
"port": "80",
},
},
Config: map[string]interface{}{
"port": 80,
},
Diff: nil,
Err: false,
},
{
Schema: map[string]*Schema{
"availability_zone": &Schema{
Type: TypeString,
Computed: true,
ComputedWhen: []string{"port"},
},
"port": &Schema{
Type: TypeInt,
Optional: true,
},
},
State: &terraform.ResourceState{
Attributes: map[string]string{
"port": "80",
},
},
Config: map[string]interface{}{
"port": 80,
},
Diff: &terraform.ResourceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": &terraform.ResourceAttrDiff{
NewComputed: true,
},
},
},
Err: false,
},
} }
for i, tc := range cases { for i, tc := range cases {