mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-21 18:10:30 -04:00
1003 lines
28 KiB
Go
1003 lines
28 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package mocking
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
)
|
|
|
|
var (
|
|
normalAttributes = map[string]*configschema.Attribute{
|
|
"id": {
|
|
Type: cty.String,
|
|
},
|
|
"value": {
|
|
Type: cty.String,
|
|
},
|
|
}
|
|
|
|
computedAttributes = map[string]*configschema.Attribute{
|
|
"id": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
},
|
|
"value": {
|
|
Type: cty.String,
|
|
},
|
|
}
|
|
|
|
normalBlock = configschema.Block{
|
|
Attributes: normalAttributes,
|
|
}
|
|
|
|
computedBlock = configschema.Block{
|
|
Attributes: computedAttributes,
|
|
}
|
|
)
|
|
|
|
func TestComputedValuesForDataSource(t *testing.T) {
|
|
tcs := map[string]struct {
|
|
target cty.Value
|
|
with cty.Value
|
|
schema *configschema.Block
|
|
expected cty.Value
|
|
expectedFailures []string
|
|
}{
|
|
"nil_target_no_unknowns": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &normalBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
"empty_target_no_unknowns": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.EmptyObjectVal,
|
|
schema: &normalBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
"basic_computed_attribute_preset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &computedBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
"basic_computed_attribute_random": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &computedBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
"basic_computed_attribute_supplied": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
schema: &computedBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
"nested_single_block_preset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingSingle,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_single_block_supplied": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingSingle,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_list_block_preset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("amyllmyg"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_list_block_supplied": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_set_block_preset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("amyllmyg"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_set_block_supplied": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_map_block_preset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("amyllmyg"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_map_block_supplied": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_single_attribute": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSingle,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_single_attribute_generated": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSingle,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("amyllmyg"),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_single_attribute_computed": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("hello"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSingle,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("hello"),
|
|
"value": cty.StringVal("ssnk9qhr"),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_list_attribute": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_list_attribute_generated": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"nested_list_attribute_computed": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ListValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"nested_set_attribute": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_set_attribute_generated": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"nested_set_attribute_computed": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Set(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.SetValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"nested_map_attribute": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
"two": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
"value": cty.StringVal("two"),
|
|
}),
|
|
}),
|
|
}),
|
|
},
|
|
"nested_map_attribute_generated": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.NilVal,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"nested_map_attribute_computed": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.NullVal(cty.Map(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
}))),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("myvalue"),
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapValEmpty(cty.Object(map[string]cty.Type{
|
|
"id": cty.String,
|
|
"value": cty.String,
|
|
})),
|
|
}),
|
|
},
|
|
"invalid_replacement_path": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.StringVal("Hello, world!"),
|
|
schema: &normalBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("kj87eb9"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
expectedFailures: []string{
|
|
"The requested replacement value must be an object type, but was string.",
|
|
},
|
|
},
|
|
"invalid_replacement_path_nested": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.StringVal("Hello, world!"),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested_object": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"id": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
},
|
|
},
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
}),
|
|
}),
|
|
}),
|
|
expectedFailures: []string{
|
|
"Terraform expected an object type for attribute \".nested_object[...]\" defined within the mocked data at :0,0-0, but found string.",
|
|
},
|
|
},
|
|
"invalid_replacement_path_nested_block": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.StringVal("Hello, world!"),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"nested_object": {
|
|
Block: configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"id": {
|
|
Type: cty.String,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
Nesting: configschema.NestingSet,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested_object": cty.SetVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
}),
|
|
}),
|
|
}),
|
|
expectedFailures: []string{
|
|
"Terraform expected an object type for attribute \".nested_object[...]\" defined within the mocked data at :0,0-0, but found string.",
|
|
},
|
|
},
|
|
"invalid_replacement_type": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.ListValEmpty(cty.String),
|
|
}),
|
|
schema: &computedBlock,
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("Hello, world!"),
|
|
}),
|
|
expectedFailures: []string{
|
|
"Terraform could not compute a value for the target type string with the mocked data defined at :0,0-0 with the attribute \".id\": string required, but have list of string.",
|
|
},
|
|
},
|
|
"invalid_replacement_type_nested": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.EmptyObjectVal,
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"nested": {
|
|
NestedType: &configschema.Object{
|
|
Attributes: computedAttributes,
|
|
Nesting: configschema.NestingMap,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"nested": cty.MapVal(map[string]cty.Value{
|
|
"one": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
}),
|
|
}),
|
|
expectedFailures: []string{
|
|
`Terraform could not compute a value for the target type string with the mocked data defined at :0,0-0 with the attribute ".nested[\"one\"].id": string required, but have object.`,
|
|
},
|
|
},
|
|
"invalid_replacement_type_nested_block": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.NullVal(cty.String),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
}),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.EmptyObjectVal,
|
|
}),
|
|
}),
|
|
schema: &configschema.Block{
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
"block": {
|
|
Block: computedBlock,
|
|
Nesting: configschema.NestingList,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"block": cty.ListVal([]cty.Value{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"id": cty.StringVal("ssnk9qhr"),
|
|
"value": cty.StringVal("one"),
|
|
}),
|
|
}),
|
|
}),
|
|
expectedFailures: []string{
|
|
"Terraform could not compute a value for the target type string with the mocked data defined at :0,0-0 with the attribute \".block[0].id\": string required, but have object.",
|
|
},
|
|
},
|
|
"dynamic_attribute_unset": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"dynamic_attribute": cty.NullVal(cty.DynamicPseudoType),
|
|
}),
|
|
with: cty.EmptyObjectVal,
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"dynamic_attribute": {
|
|
Type: cty.DynamicPseudoType,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"dynamic_attribute": cty.NullVal(cty.DynamicPseudoType),
|
|
}),
|
|
},
|
|
"dynamic_attribute_set": {
|
|
target: cty.ObjectVal(map[string]cty.Value{
|
|
"dynamic_attribute": cty.NullVal(cty.DynamicPseudoType),
|
|
}),
|
|
with: cty.ObjectVal(map[string]cty.Value{
|
|
"dynamic_attribute": cty.StringVal("Hello, world!"),
|
|
}),
|
|
schema: &configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"dynamic_attribute": {
|
|
Type: cty.DynamicPseudoType,
|
|
Computed: true,
|
|
},
|
|
},
|
|
},
|
|
expected: cty.ObjectVal(map[string]cty.Value{
|
|
"dynamic_attribute": cty.StringVal("Hello, world!"),
|
|
}),
|
|
},
|
|
}
|
|
|
|
for name, tc := range tcs {
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
// We'll just make sure that any random strings are deterministic.
|
|
testRand = rand.New(rand.NewSource(0))
|
|
defer func() {
|
|
testRand = nil
|
|
}()
|
|
|
|
actual, diags := ComputedValuesForDataSource(tc.target, &MockedData{
|
|
Value: tc.with,
|
|
}, tc.schema)
|
|
|
|
var actualFailures []string
|
|
for _, diag := range diags {
|
|
actualFailures = append(actualFailures, diag.Description().Detail)
|
|
}
|
|
if diff := cmp.Diff(tc.expectedFailures, actualFailures); len(diff) > 0 {
|
|
t.Errorf("unexpected failures\nexpected:\n%s\nactual:\n%s\ndiff:\n%s", tc.expectedFailures, actualFailures, diff)
|
|
}
|
|
|
|
if actual.Equals(tc.expected).False() {
|
|
t.Errorf("\nexpected: (%s)\nactual: (%s)", tc.expected.GoString(), actual.GoString())
|
|
}
|
|
})
|
|
}
|
|
}
|