1570 lines
43 KiB
Go
1570 lines
43 KiB
Go
package objchange
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/apparentlymart/go-dump/dump"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
)
|
|
|
|
func TestProposedNew(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Schema *configschema.Block
|
|
Prior cty.Value
|
|
Config cty.Value
|
|
Want cty.Value
|
|
}{
|
|
"empty": {
|
|
&configschema.Block{},
|
|
cty.EmptyObjectVal,
|
|
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,
|
|
},
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("hello"),
|
|
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"blop": cty.String,
|
|
})),
|
|
"bar": cty.NullVal(cty.String),
|
|
"baz": cty.ObjectVal(map[string]cty.Value{
|
|
"boz": cty.StringVal("world"),
|
|
|
|
// An unknown in the config represents a situation where
|
|
// an argument is explicitly set to an expression result
|
|
// that is derived from an unknown value. This is distinct
|
|
// from leaving it null, which allows the provider itself
|
|
// to decide the value during PlanResourceChange.
|
|
"biz": cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("hello"),
|
|
|
|
// unset computed attributes are null in the proposal; provider
|
|
// usually changes them to "unknown" during PlanResourceChange,
|
|
// to indicate that the value will be decided during apply.
|
|
"bar": cty.NullVal(cty.String),
|
|
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"blop": cty.String,
|
|
})),
|
|
|
|
"baz": cty.ObjectVal(map[string]cty.Value{
|
|
"boz": cty.StringVal("world"),
|
|
"biz": cty.UnknownVal(cty.String), // explicit unknown preserved from config
|
|
}),
|
|
}),
|
|
},
|
|
"null block remains null": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"blop": cty.String,
|
|
})),
|
|
"baz": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"boz": cty.String,
|
|
})),
|
|
}),
|
|
// The bloop attribue and baz block does not exist in the config,
|
|
// and therefore shouldn't be planned.
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"blop": cty.String,
|
|
})),
|
|
"baz": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"boz": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"no prior with set": {
|
|
// This one is here because our handling of sets is more complex
|
|
// than others (due to the fuzzy correlation heuristic) and
|
|
// historically that caused us some panic-related grief.
|
|
&configschema.Block{
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"boz": cty.StringVal("world"),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blub"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"boz": cty.StringVal("world"),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blub"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"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,
|
|
},
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bonjour"),
|
|
"bar": cty.StringVal("petit dejeuner"),
|
|
"baz": cty.StringVal("grande dejeuner"),
|
|
"boz": cty.StringVal("a la monde"),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("hello"),
|
|
"bar": cty.NullVal(cty.String),
|
|
"baz": cty.NullVal(cty.String),
|
|
"boz": cty.StringVal("world"),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bleep"),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("hello"),
|
|
"bar": cty.StringVal("petit dejeuner"),
|
|
"baz": cty.StringVal("grande dejeuner"),
|
|
"boz": cty.StringVal("world"),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bleep"),
|
|
}),
|
|
}),
|
|
},
|
|
"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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
"bleep": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
"bleep": cty.StringVal("beep"),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
"bleep": cty.StringVal("beep"),
|
|
}),
|
|
}),
|
|
},
|
|
"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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingList,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("baz"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("baz"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("baz"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingList,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.DynamicPseudoType,
|
|
Required: true,
|
|
},
|
|
"blub": {
|
|
Type: cty.DynamicPseudoType,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
"blub": cty.StringVal("glub"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("baz"),
|
|
"blub": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
"blub": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("bar"),
|
|
"blub": cty.NullVal(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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingMap,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.StringVal("boot"),
|
|
}),
|
|
}),
|
|
"bloop": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
}),
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blub"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blub"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blub"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingMap,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.DynamicPseudoType,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: 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.StringVal("boop"),
|
|
}),
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("boot")}),
|
|
}),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
}),
|
|
"b": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.NumberIntVal(13),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.List(cty.String)),
|
|
}),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blep"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.NumberIntVal(13),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bap"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.List(cty.String)),
|
|
}),
|
|
}),
|
|
"bloop": cty.ObjectVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("blep"),
|
|
}),
|
|
"c": cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.NumberIntVal(13),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"prior nested set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {
|
|
// This non-computed attribute will serve
|
|
// as our matching key for propagating
|
|
// "baz" from elements in the prior value.
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
"baz": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
"bleep": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("blep"),
|
|
"baz": cty.StringVal("boot"),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glubglub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glubglub"),
|
|
"bleep": cty.StringVal("beep"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glubglub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("beep"),
|
|
"baz": cty.StringVal("boop"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("bosh"),
|
|
"baz": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glubglub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.StringVal("glub"),
|
|
"bleep": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"sets differing only by unknown": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"multi": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"optional": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bloop": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"blop": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"multi": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"multi": cty.SetVal([]cty.Value{
|
|
// These remain distinct because unknown values never
|
|
// compare equal. They may be consolidated together once
|
|
// the values become known, though.
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
"bloop": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.UnknownVal(cty.String),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"blop": cty.UnknownVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested list in set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"bar": {
|
|
Nesting: configschema.NestingList,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"baz": {
|
|
Type: cty.String,
|
|
},
|
|
"qux": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("beep"),
|
|
"qux": cty.StringVal("boop"),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("beep"),
|
|
"qux": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("beep"),
|
|
"qux": cty.StringVal("boop"),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"empty nested list in set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"bar": {
|
|
Nesting: configschema.NestingList,
|
|
Block: configschema.Block{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ListValEmpty((&configschema.Block{}).ImpliedType()),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested list with dynamic in set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"bar": {
|
|
Nesting: configschema.NestingList,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"baz": {
|
|
Type: cty.DynamicPseudoType,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.TupleVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested map with dynamic in set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"bar": {
|
|
Nesting: configschema.NestingMap,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"baz": {
|
|
Type: cty.DynamicPseudoType,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ObjectVal(map[string]cty.Value{
|
|
"bing": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
"bang": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ObjectVal(map[string]cty.Value{
|
|
"bing": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ObjectVal(map[string]cty.Value{
|
|
"bing": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.ListVal([]cty.Value{cty.StringVal("true")}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"empty nested map in set": {
|
|
&configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"foo": {
|
|
Nesting: configschema.NestingSet,
|
|
Block: configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"bar": {
|
|
Nesting: configschema.NestingMap,
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"baz": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
"baz": cty.String,
|
|
})),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.MapVal(map[string]cty.Value{
|
|
"bing": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.MapVal(map[string]cty.Value{
|
|
"bing": cty.ObjectVal(map[string]cty.Value{
|
|
"baz": cty.StringVal("true"),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
// This example has a mixture of optional, computed and required in a deeply-nested NestedType attribute
|
|
"deeply NestedType": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: testAttributes,
|
|
},
|
|
Required: true,
|
|
},
|
|
"baz": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: testAttributes,
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
// prior
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.NullVal(cty.DynamicPseudoType),
|
|
"baz": cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.NullVal(cty.String),
|
|
"computed": cty.StringVal("hello"),
|
|
"optional_computed": cty.StringVal("prior"),
|
|
"required": cty.StringVal("present"),
|
|
}),
|
|
}),
|
|
}),
|
|
// config
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.UnknownVal(cty.Object(map[string]cty.Type{ // explicit unknown from the config
|
|
"optional": cty.String,
|
|
"computed": cty.String,
|
|
"optional_computed": cty.String,
|
|
"required": cty.String,
|
|
})),
|
|
"baz": cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.NullVal(cty.String),
|
|
"computed": cty.NullVal(cty.String),
|
|
"optional_computed": cty.StringVal("hello"),
|
|
"required": cty.StringVal("present"),
|
|
}),
|
|
}),
|
|
}),
|
|
// want
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.UnknownVal(cty.Object(map[string]cty.Type{ // explicit unknown preserved from the config
|
|
"optional": cty.String,
|
|
"computed": cty.String,
|
|
"optional_computed": cty.String,
|
|
"required": cty.String,
|
|
})),
|
|
"baz": cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.NullVal(cty.String), // config is null
|
|
"computed": cty.StringVal("hello"), // computed values come from prior
|
|
"optional_computed": cty.StringVal("hello"), // config takes precedent over prior in opt+computed
|
|
"required": cty.StringVal("present"), // value from config
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"deeply nested set": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: testAttributes,
|
|
},
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
// prior values
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.StringVal("prior"),
|
|
"computed": cty.StringVal("prior"),
|
|
"optional_computed": cty.StringVal("prior"),
|
|
"required": cty.StringVal("prior"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.StringVal("other_prior"),
|
|
"computed": cty.StringVal("other_prior"),
|
|
"optional_computed": cty.StringVal("other_prior"),
|
|
"required": cty.StringVal("other_prior"),
|
|
})}),
|
|
}),
|
|
}),
|
|
}),
|
|
// config differs from prior
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.StringVal("configured"),
|
|
"computed": cty.NullVal(cty.String), // computed attrs are null in config
|
|
"optional_computed": cty.StringVal("configured"),
|
|
"required": cty.StringVal("configured"),
|
|
})}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.NullVal(cty.String), // explicit null in config
|
|
"computed": cty.NullVal(cty.String), // computed attrs are null in config
|
|
"optional_computed": cty.StringVal("other_configured"),
|
|
"required": cty.StringVal("other_configured"),
|
|
})}),
|
|
}),
|
|
}),
|
|
}),
|
|
// want:
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.StringVal("configured"),
|
|
"computed": cty.NullVal(cty.String),
|
|
"optional_computed": cty.StringVal("configured"),
|
|
"required": cty.StringVal("configured"),
|
|
})}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.NullVal(cty.String), // explicit null in config is preserved
|
|
"computed": cty.NullVal(cty.String),
|
|
"optional_computed": cty.StringVal("other_configured"),
|
|
"required": cty.StringVal("other_configured"),
|
|
})}),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"expected null NestedTypes": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"single": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
"list": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingList,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
"set": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
"map": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingMap,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
"nested_map": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingMap,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"inner": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSingle,
|
|
Attributes: testAttributes,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"single": cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
|
|
"list": cty.ListVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
|
|
"map": cty.MapVal(map[string]cty.Value{
|
|
"map_entry": cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")}),
|
|
}),
|
|
"set": cty.SetVal([]cty.Value{cty.ObjectVal(map[string]cty.Value{"bar": cty.StringVal("baz")})}),
|
|
"nested_map": cty.MapVal(map[string]cty.Value{
|
|
"a": cty.ObjectVal(map[string]cty.Value{
|
|
"inner": cty.ObjectVal(map[string]cty.Value{
|
|
"optional": cty.StringVal("foo"),
|
|
"computed": cty.StringVal("foo"),
|
|
"optional_computed": cty.StringVal("foo"),
|
|
"required": cty.StringVal("foo"),
|
|
}),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"single": cty.NullVal(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"set": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"nested_map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
|
|
"inner": cty.Object(map[string]cty.Type{
|
|
"optional": cty.String,
|
|
"computed": cty.String,
|
|
"optional_computed": cty.String,
|
|
"required": cty.String,
|
|
}),
|
|
}))),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"single": cty.NullVal(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
"list": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"set": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{"bar": cty.String}))),
|
|
"nested_map": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
|
|
"inner": cty.Object(map[string]cty.Type{
|
|
"optional": cty.String,
|
|
"computed": cty.String,
|
|
"optional_computed": cty.String,
|
|
"required": cty.String,
|
|
}),
|
|
}))),
|
|
}),
|
|
},
|
|
"expected empty NestedTypes": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"set": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
"map": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingMap,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {Type: cty.String},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"map": cty.MapValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
"set": cty.SetValEmpty(cty.Object(map[string]cty.Type{"bar": cty.String})),
|
|
}),
|
|
},
|
|
"optional types set replacement": {
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"set": {
|
|
NestedType: &configschema.Object{
|
|
Nesting: configschema.NestingSet,
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"set": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("old"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"set": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("new"),
|
|
}),
|
|
}),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"set": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.StringVal("new"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got := ProposedNew(test.Schema, test.Prior, test.Config)
|
|
if !got.RawEquals(test.Want) {
|
|
t.Errorf("wrong result\ngot: %swant: %s", dump.Value(got), dump.Value(test.Want))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
var testAttributes = map[string]*configschema.Attribute{
|
|
"optional": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
"computed": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
},
|
|
"optional_computed": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
"required": {
|
|
Type: cty.String,
|
|
Required: true,
|
|
},
|
|
}
|