Merge pull request #15723 from hashicorp/f-get-boolean-non-default

core: Add `GetOkExists` schema function
This commit is contained in:
Jake Champlin 2017-08-03 18:06:17 -04:00 committed by GitHub
commit 3600f0b730
2 changed files with 268 additions and 0 deletions

View File

@ -104,6 +104,22 @@ func (d *ResourceData) GetOk(key string) (interface{}, bool) {
return r.Value, exists return r.Value, exists
} }
// GetOkExists returns the data for a given key and whether or not the key
// has been set to a non-zero value. This is only useful for determining
// if boolean attributes have been set, if they are Optional but do not
// have a Default value.
//
// This is nearly the same function as GetOk, yet it does not check
// for the zero value of the attribute's type. This allows for attributes
// without a default, to fully check for a literal assignment, regardless
// of the zero-value for that type.
// This should only be used if absolutely required/needed.
func (d *ResourceData) GetOkExists(key string) (interface{}, bool) {
r := d.getRaw(key, getSourceSet)
exists := r.Exists && !r.Computed
return r.Value, exists
}
func (d *ResourceData) getRaw(key string, level getSource) getResult { func (d *ResourceData) getRaw(key string, level getSource) getResult {
var parts []string var parts []string
if key != "" { if key != "" {

View File

@ -1082,6 +1082,258 @@ func TestResourceDataGetOk(t *testing.T) {
} }
} }
func TestResourceDataGetOkExists(t *testing.T) {
cases := []struct {
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Diff *terraform.InstanceDiff
Key string
Value interface{}
Ok bool
}{
/*
* Primitives
*/
{
Name: "string-literal-empty",
Schema: map[string]*Schema{
"availability_zone": {
Type: TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
State: nil,
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": {
Old: "",
New: "",
},
},
},
Key: "availability_zone",
Value: "",
Ok: true,
},
{
Name: "string-computed-empty",
Schema: map[string]*Schema{
"availability_zone": {
Type: TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
State: nil,
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": {
Old: "",
New: "",
NewComputed: true,
},
},
},
Key: "availability_zone",
Value: "",
Ok: false,
},
{
Name: "string-optional-computed-nil-diff",
Schema: map[string]*Schema{
"availability_zone": {
Type: TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
State: nil,
Diff: nil,
Key: "availability_zone",
Value: "",
Ok: false,
},
/*
* Lists
*/
{
Name: "list-optional",
Schema: map[string]*Schema{
"ports": {
Type: TypeList,
Optional: true,
Elem: &Schema{Type: TypeInt},
},
},
State: nil,
Diff: nil,
Key: "ports",
Value: []interface{}{},
Ok: false,
},
/*
* Map
*/
{
Name: "map-optional",
Schema: map[string]*Schema{
"ports": {
Type: TypeMap,
Optional: true,
},
},
State: nil,
Diff: nil,
Key: "ports",
Value: map[string]interface{}{},
Ok: false,
},
/*
* Set
*/
{
Name: "set-optional",
Schema: map[string]*Schema{
"ports": {
Type: TypeSet,
Optional: true,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int { return a.(int) },
},
},
State: nil,
Diff: nil,
Key: "ports",
Value: []interface{}{},
Ok: false,
},
{
Name: "set-optional-key",
Schema: map[string]*Schema{
"ports": {
Type: TypeSet,
Optional: true,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int { return a.(int) },
},
},
State: nil,
Diff: nil,
Key: "ports.0",
Value: 0,
Ok: false,
},
{
Name: "bool-literal-empty",
Schema: map[string]*Schema{
"availability_zone": {
Type: TypeBool,
Optional: true,
Computed: true,
ForceNew: true,
},
},
State: nil,
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": {
Old: "",
New: "",
},
},
},
Key: "availability_zone",
Value: false,
Ok: true,
},
{
Name: "bool-literal-set",
Schema: map[string]*Schema{
"availability_zone": {
Type: TypeBool,
Optional: true,
Computed: true,
ForceNew: true,
},
},
State: nil,
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"availability_zone": {
New: "true",
},
},
},
Key: "availability_zone",
Value: true,
Ok: true,
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) {
d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
if err != nil {
t.Fatalf("%s err: %s", tc.Name, err)
}
v, ok := d.GetOkExists(tc.Key)
if s, ok := v.(*Set); ok {
v = s.List()
}
if !reflect.DeepEqual(v, tc.Value) {
t.Fatalf("Bad %s: \n%#v", tc.Name, v)
}
if ok != tc.Ok {
t.Fatalf("%s: expected ok: %t, got: %t", tc.Name, tc.Ok, ok)
}
})
}
}
func TestResourceDataTimeout(t *testing.T) { func TestResourceDataTimeout(t *testing.T) {
cases := []struct { cases := []struct {
Name string Name string