2017-10-04 20:27:51 +02:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2018-07-12 02:59:32 +02:00
|
|
|
"github.com/google/go-cmp/cmp"
|
2017-10-04 20:27:51 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2018-07-05 19:33:29 +02:00
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
2017-10-04 20:27:51 +02:00
|
|
|
)
|
|
|
|
|
2018-07-12 02:59:32 +02:00
|
|
|
// add the implicit "id" attribute for test resources
|
|
|
|
func testResource(block *configschema.Block) *configschema.Block {
|
|
|
|
if block.Attributes == nil {
|
|
|
|
block.Attributes = make(map[string]*configschema.Attribute)
|
|
|
|
}
|
|
|
|
|
|
|
|
if block.BlockTypes == nil {
|
|
|
|
block.BlockTypes = make(map[string]*configschema.NestedBlock)
|
|
|
|
}
|
|
|
|
|
|
|
|
if block.Attributes["id"] == nil {
|
|
|
|
block.Attributes["id"] = &configschema.Attribute{
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return block
|
|
|
|
}
|
|
|
|
|
2017-10-04 20:27:51 +02:00
|
|
|
func TestSchemaMapCoreConfigSchema(t *testing.T) {
|
|
|
|
tests := map[string]struct {
|
|
|
|
Schema map[string]*Schema
|
|
|
|
Want *configschema.Block
|
|
|
|
}{
|
|
|
|
"empty": {
|
|
|
|
map[string]*Schema{},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{}),
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
|
|
|
"primitives": {
|
|
|
|
map[string]*Schema{
|
|
|
|
"int": {
|
2018-03-16 18:43:35 +01:00
|
|
|
Type: TypeInt,
|
|
|
|
Required: true,
|
|
|
|
Description: "foo bar baz",
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
|
|
|
"float": {
|
|
|
|
Type: TypeFloat,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"bool": {
|
|
|
|
Type: TypeBool,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"string": {
|
|
|
|
Type: TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2017-10-04 20:27:51 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"int": {
|
2018-03-16 18:43:35 +01:00
|
|
|
Type: cty.Number,
|
|
|
|
Required: true,
|
|
|
|
Description: "foo bar baz",
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
|
|
|
"float": {
|
|
|
|
Type: cty.Number,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"bool": {
|
|
|
|
Type: cty.Bool,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"string": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
|
|
|
"simple collections": {
|
|
|
|
map[string]*Schema{
|
|
|
|
"list": {
|
|
|
|
Type: TypeList,
|
|
|
|
Required: true,
|
|
|
|
Elem: &Schema{
|
|
|
|
Type: TypeInt,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Type: TypeSet,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &Schema{
|
|
|
|
Type: TypeString,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Type: TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &Schema{
|
|
|
|
Type: TypeBool,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"map_default_type": {
|
|
|
|
Type: TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
// Maps historically don't have elements because we
|
|
|
|
// assumed they would be strings, so this needs to work
|
|
|
|
// for pre-existing schemas.
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2017-10-04 20:27:51 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"list": {
|
|
|
|
Type: cty.List(cty.Number),
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Type: cty.Set(cty.String),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Type: cty.Map(cty.Bool),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"map_default_type": {
|
|
|
|
Type: cty.Map(cty.String),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
2018-06-02 02:32:01 +02:00
|
|
|
"incorrectly-specified collections": {
|
|
|
|
// Historically we tolerated setting a type directly as the Elem
|
|
|
|
// attribute, rather than a Schema object. This is common enough
|
|
|
|
// in existing provider code that we must support it as an alias
|
|
|
|
// for a schema object with the given type.
|
|
|
|
map[string]*Schema{
|
|
|
|
"list": {
|
|
|
|
Type: TypeList,
|
|
|
|
Required: true,
|
|
|
|
Elem: TypeInt,
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Type: TypeSet,
|
|
|
|
Optional: true,
|
|
|
|
Elem: TypeString,
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Type: TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
Elem: TypeBool,
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2018-06-02 02:32:01 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"list": {
|
|
|
|
Type: cty.List(cty.Number),
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Type: cty.Set(cty.String),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Type: cty.Map(cty.Bool),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2018-06-02 02:32:01 +02:00
|
|
|
},
|
2017-10-04 20:27:51 +02:00
|
|
|
"sub-resource collections": {
|
|
|
|
map[string]*Schema{
|
|
|
|
"list": {
|
|
|
|
Type: TypeList,
|
|
|
|
Required: true,
|
|
|
|
Elem: &Resource{
|
|
|
|
Schema: map[string]*Schema{},
|
|
|
|
},
|
|
|
|
MinItems: 1,
|
|
|
|
MaxItems: 2,
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Type: TypeSet,
|
|
|
|
Required: true,
|
|
|
|
Elem: &Resource{
|
|
|
|
Schema: map[string]*Schema{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Type: TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &Resource{
|
|
|
|
Schema: map[string]*Schema{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2017-10-04 20:27:51 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"list": {
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
Block: configschema.Block{},
|
|
|
|
MinItems: 1,
|
|
|
|
MaxItems: 2,
|
|
|
|
},
|
|
|
|
"set": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{},
|
|
|
|
MinItems: 1, // because schema is Required
|
|
|
|
},
|
|
|
|
"map": {
|
|
|
|
Nesting: configschema.NestingMap,
|
|
|
|
Block: configschema.Block{},
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
|
|
|
"nested attributes and blocks": {
|
|
|
|
map[string]*Schema{
|
|
|
|
"foo": {
|
|
|
|
Type: TypeList,
|
|
|
|
Required: true,
|
|
|
|
Elem: &Resource{
|
|
|
|
Schema: map[string]*Schema{
|
|
|
|
"bar": {
|
|
|
|
Type: TypeList,
|
|
|
|
Required: true,
|
|
|
|
Elem: &Schema{
|
|
|
|
Type: TypeList,
|
|
|
|
Elem: &Schema{
|
|
|
|
Type: TypeString,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"baz": {
|
|
|
|
Type: TypeSet,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &Resource{
|
|
|
|
Schema: map[string]*Schema{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2017-10-04 20:27:51 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"foo": &configschema.NestedBlock{
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"bar": {
|
|
|
|
Type: cty.List(cty.List(cty.String)),
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"baz": {
|
|
|
|
Nesting: configschema.NestingSet,
|
|
|
|
Block: configschema.Block{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
MinItems: 1, // because schema is Required
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-04 20:27:51 +02:00
|
|
|
},
|
2017-10-04 20:38:04 +02:00
|
|
|
"sensitive": {
|
|
|
|
map[string]*Schema{
|
|
|
|
"string": {
|
|
|
|
Type: TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Sensitive: true,
|
|
|
|
},
|
|
|
|
},
|
2018-07-12 02:59:32 +02:00
|
|
|
testResource(&configschema.Block{
|
2017-10-04 20:38:04 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"string": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
Sensitive: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{},
|
2018-07-12 02:59:32 +02:00
|
|
|
}),
|
2017-10-04 20:38:04 +02:00
|
|
|
},
|
2017-10-04 20:27:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for name, test := range tests {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2018-07-19 19:53:31 +02:00
|
|
|
got := (&Resource{Schema: test.Schema}).CoreConfigSchema()
|
|
|
|
if !cmp.Equal(got, test.Want, equateEmpty, typeComparer) {
|
|
|
|
t.Error(cmp.Diff(got, test.Want, equateEmpty, typeComparer))
|
2017-10-04 20:27:51 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|