2019-02-08 02:24:36 +01:00
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSetUnknowns(t *testing.T) {
|
|
|
|
for n, tc := range map[string]struct {
|
|
|
|
Schema *configschema.Block
|
|
|
|
Val cty.Value
|
|
|
|
Expected cty.Value
|
|
|
|
}{
|
|
|
|
"empty": {
|
|
|
|
&configschema.Block{},
|
|
|
|
cty.EmptyObjectVal,
|
|
|
|
cty.EmptyObjectVal,
|
|
|
|
},
|
|
|
|
"no prior": {
|
|
|
|
&configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"baz": {
|
|
|
|
Nesting: configschema.NestingSingle,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"boz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"biz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2019-02-08 20:46:29 +01:00
|
|
|
cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"foo": cty.String,
|
|
|
|
"bar": cty.String,
|
|
|
|
"baz": cty.Object(map[string]cty.Type{
|
|
|
|
"boz": cty.String,
|
|
|
|
"biz": cty.String,
|
|
|
|
}),
|
|
|
|
})),
|
2019-02-08 02:24:36 +01:00
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
2019-02-08 20:46:29 +01:00
|
|
|
"foo": cty.NullVal(cty.String),
|
2019-02-08 02:24:36 +01:00
|
|
|
"bar": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
},
|
2019-02-08 20:46:29 +01:00
|
|
|
"null stays null": {
|
|
|
|
// if the object has no computed attributes, it should stay null
|
|
|
|
&configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"baz": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"boz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"foo": cty.String,
|
|
|
|
"baz": cty.Set(cty.Object(map[string]cty.Type{
|
|
|
|
"boz": cty.String,
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"foo": cty.String,
|
|
|
|
"baz": cty.Set(cty.Object(map[string]cty.Type{
|
|
|
|
"boz": cty.String,
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
},
|
2019-02-08 02:24:36 +01:00
|
|
|
"no prior with set": {
|
|
|
|
// the set value should remain null
|
|
|
|
&configschema.Block{
|
2019-02-08 20:46:29 +01:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
2019-02-08 02:24:36 +01:00
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"baz": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"boz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2019-02-08 20:46:29 +01:00
|
|
|
cty.NullVal(cty.Object(map[string]cty.Type{
|
|
|
|
"foo": cty.String,
|
|
|
|
"baz": cty.Set(cty.Object(map[string]cty.Type{
|
|
|
|
"boz": cty.String,
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
2019-02-08 02:24:36 +01:00
|
|
|
},
|
|
|
|
"prior attributes": {
|
|
|
|
&configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"boz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.StringVal("bonjour"),
|
|
|
|
"bar": cty.StringVal("petit dejeuner"),
|
|
|
|
"baz": cty.StringVal("grande dejeuner"),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.StringVal("bonjour"),
|
|
|
|
"bar": cty.StringVal("petit dejeuner"),
|
|
|
|
"baz": cty.StringVal("grande dejeuner"),
|
|
|
|
"boz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"prior nested single": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingSingle,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("beep"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("beep"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"prior nested list": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("bap"),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ListVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("bap"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"prior nested map": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.NullVal(cty.String),
|
|
|
|
"baz": cty.StringVal("boop"),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.UnknownVal(cty.String),
|
|
|
|
"baz": cty.StringVal("boop"),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"prior nested set": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("blep"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"sets differing only by unknown": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.SetVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
2019-02-08 20:46:29 +01:00
|
|
|
"prior nested list with dynamic": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.DynamicPseudoType,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.TupleVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.NullVal(cty.String),
|
|
|
|
"baz": cty.NumberIntVal(8),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.TupleVal([]cty.Value{
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.UnknownVal(cty.String),
|
|
|
|
"baz": cty.NumberIntVal(8),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
"prior nested map with dynamic": {
|
|
|
|
&configschema.Block{
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": {
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: cty.DynamicPseudoType,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("beep"),
|
|
|
|
"baz": cty.NullVal(cty.DynamicPseudoType),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.NumberIntVal(8),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("beep"),
|
|
|
|
"baz": cty.UnknownVal(cty.DynamicPseudoType),
|
|
|
|
}),
|
|
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"bar": cty.StringVal("boop"),
|
|
|
|
"baz": cty.NumberIntVal(8),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
},
|
2019-02-08 02:24:36 +01:00
|
|
|
} {
|
|
|
|
t.Run(n, func(t *testing.T) {
|
2019-02-08 20:46:29 +01:00
|
|
|
got := SetUnknowns(tc.Val, tc.Schema)
|
|
|
|
if !got.RawEquals(tc.Expected) {
|
|
|
|
t.Fatalf("\nexpected: %#v\ngot: %#v\n", tc.Expected, got)
|
2019-02-08 02:24:36 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|