terraform/internal/command/jsonplan/plan_test.go

520 lines
11 KiB
Go

package jsonplan
import (
"encoding/json"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty/cty"
)
func TestOmitUnknowns(t *testing.T) {
tests := []struct {
Input cty.Value
Want cty.Value
}{
{
cty.StringVal("hello"),
cty.StringVal("hello"),
},
{
cty.NullVal(cty.String),
cty.NullVal(cty.String),
},
{
cty.UnknownVal(cty.String),
cty.NilVal,
},
{
cty.ListValEmpty(cty.String),
cty.EmptyTupleVal,
},
{
cty.ListVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
},
{
cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
},
{
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
},
{
cty.ListVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
},
//
{
cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.UnknownVal(cty.String)}),
cty.TupleVal([]cty.Value{
cty.StringVal("hello"),
cty.NullVal(cty.String),
}),
},
{
cty.MapVal(map[string]cty.Value{
"hello": cty.True,
"world": cty.UnknownVal(cty.Bool),
}),
cty.ObjectVal(map[string]cty.Value{
"hello": cty.True,
}),
},
{
cty.SetVal([]cty.Value{
cty.StringVal("dev"),
cty.StringVal("foo"),
cty.StringVal("stg"),
cty.UnknownVal(cty.String),
}),
cty.TupleVal([]cty.Value{
cty.StringVal("dev"),
cty.StringVal("foo"),
cty.StringVal("stg"),
}),
},
{
cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.UnknownVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("known"),
}),
}),
cty.TupleVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("known"),
}),
cty.EmptyObjectVal,
}),
},
}
for _, test := range tests {
got := omitUnknowns(test.Input)
if !reflect.DeepEqual(got, test.Want) {
t.Errorf(
"wrong result\ninput: %#v\ngot: %#v\nwant: %#v",
test.Input, got, test.Want,
)
}
}
}
func TestUnknownAsBool(t *testing.T) {
tests := []struct {
Input cty.Value
Want cty.Value
}{
{
cty.StringVal("hello"),
cty.False,
},
{
cty.NullVal(cty.String),
cty.False,
},
{
cty.UnknownVal(cty.String),
cty.True,
},
{
cty.NullVal(cty.DynamicPseudoType),
cty.False,
},
{
cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})),
cty.False,
},
{
cty.DynamicVal,
cty.True,
},
{
cty.ListValEmpty(cty.String),
cty.EmptyTupleVal,
},
{
cty.ListVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.ListVal([]cty.Value{cty.NullVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.ListVal([]cty.Value{cty.UnknownVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.True}),
},
{
cty.SetValEmpty(cty.String),
cty.EmptyTupleVal,
},
{
cty.SetVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.SetVal([]cty.Value{cty.NullVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.SetVal([]cty.Value{cty.UnknownVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.True}),
},
{
cty.EmptyTupleVal,
cty.EmptyTupleVal,
},
{
cty.TupleVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.TupleVal([]cty.Value{cty.NullVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.TupleVal([]cty.Value{cty.UnknownVal(cty.String)}),
cty.TupleVal([]cty.Value{cty.True}),
},
{
cty.MapValEmpty(cty.String),
cty.EmptyObjectVal,
},
{
cty.MapVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
cty.EmptyObjectVal,
},
{
cty.MapVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
cty.EmptyObjectVal,
},
{
cty.MapVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
},
{
cty.EmptyObjectVal,
cty.EmptyObjectVal,
},
{
cty.ObjectVal(map[string]cty.Value{"greeting": cty.StringVal("hello")}),
cty.EmptyObjectVal,
},
{
cty.ObjectVal(map[string]cty.Value{"greeting": cty.NullVal(cty.String)}),
cty.EmptyObjectVal,
},
{
cty.ObjectVal(map[string]cty.Value{"greeting": cty.UnknownVal(cty.String)}),
cty.ObjectVal(map[string]cty.Value{"greeting": cty.True}),
},
{
cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.UnknownVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("known"),
}),
}),
cty.TupleVal([]cty.Value{
cty.EmptyObjectVal,
cty.ObjectVal(map[string]cty.Value{
"a": cty.True,
}),
}),
},
{
cty.SetVal([]cty.Value{
cty.MapValEmpty(cty.String),
cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("known"),
}),
cty.MapVal(map[string]cty.Value{
"a": cty.UnknownVal(cty.String),
}),
}),
cty.TupleVal([]cty.Value{
cty.EmptyObjectVal,
cty.ObjectVal(map[string]cty.Value{
"a": cty.True,
}),
cty.EmptyObjectVal,
}),
},
}
for _, test := range tests {
got := unknownAsBool(test.Input)
if !reflect.DeepEqual(got, test.Want) {
t.Errorf(
"wrong result\ninput: %#v\ngot: %#v\nwant: %#v",
test.Input, got, test.Want,
)
}
}
}
func TestSensitiveAsBool(t *testing.T) {
sensitive := "sensitive"
tests := []struct {
Input cty.Value
Want cty.Value
}{
{
cty.StringVal("hello"),
cty.False,
},
{
cty.NullVal(cty.String),
cty.False,
},
{
cty.StringVal("hello").Mark(sensitive),
cty.True,
},
{
cty.NullVal(cty.String).Mark(sensitive),
cty.True,
},
{
cty.NullVal(cty.DynamicPseudoType).Mark(sensitive),
cty.True,
},
{
cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})),
cty.False,
},
{
cty.NullVal(cty.Object(map[string]cty.Type{"test": cty.String})).Mark(sensitive),
cty.True,
},
{
cty.DynamicVal,
cty.False,
},
{
cty.DynamicVal.Mark(sensitive),
cty.True,
},
{
cty.ListValEmpty(cty.String),
cty.EmptyTupleVal,
},
{
cty.ListValEmpty(cty.String).Mark(sensitive),
cty.True,
},
{
cty.ListVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friend").Mark(sensitive),
}),
cty.TupleVal([]cty.Value{
cty.False,
cty.True,
}),
},
{
cty.SetValEmpty(cty.String),
cty.EmptyTupleVal,
},
{
cty.SetValEmpty(cty.String).Mark(sensitive),
cty.True,
},
{
cty.SetVal([]cty.Value{cty.StringVal("hello")}),
cty.TupleVal([]cty.Value{cty.False}),
},
{
cty.SetVal([]cty.Value{cty.StringVal("hello").Mark(sensitive)}),
cty.True,
},
{
cty.EmptyTupleVal.Mark(sensitive),
cty.True,
},
{
cty.TupleVal([]cty.Value{
cty.StringVal("hello"),
cty.StringVal("friend").Mark(sensitive),
}),
cty.TupleVal([]cty.Value{
cty.False,
cty.True,
}),
},
{
cty.MapValEmpty(cty.String),
cty.EmptyObjectVal,
},
{
cty.MapValEmpty(cty.String).Mark(sensitive),
cty.True,
},
{
cty.MapVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse"),
}),
cty.EmptyObjectVal,
},
{
cty.MapVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse").Mark(sensitive),
}),
cty.ObjectVal(map[string]cty.Value{
"animal": cty.True,
}),
},
{
cty.MapVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse").Mark(sensitive),
}).Mark(sensitive),
cty.True,
},
{
cty.EmptyObjectVal,
cty.EmptyObjectVal,
},
{
cty.ObjectVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse"),
}),
cty.EmptyObjectVal,
},
{
cty.ObjectVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse").Mark(sensitive),
}),
cty.ObjectVal(map[string]cty.Value{
"animal": cty.True,
}),
},
{
cty.ObjectVal(map[string]cty.Value{
"greeting": cty.StringVal("hello"),
"animal": cty.StringVal("horse").Mark(sensitive),
}).Mark(sensitive),
cty.True,
},
{
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.UnknownVal(cty.String),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("known").Mark(sensitive),
}),
}),
cty.TupleVal([]cty.Value{
cty.EmptyObjectVal,
cty.ObjectVal(map[string]cty.Value{
"a": cty.True,
}),
}),
},
{
cty.ListVal([]cty.Value{
cty.MapValEmpty(cty.String),
cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("known").Mark(sensitive),
}),
cty.MapVal(map[string]cty.Value{
"a": cty.UnknownVal(cty.String),
}),
}),
cty.TupleVal([]cty.Value{
cty.EmptyObjectVal,
cty.ObjectVal(map[string]cty.Value{
"a": cty.True,
}),
cty.EmptyObjectVal,
}),
},
{
cty.ObjectVal(map[string]cty.Value{
"list": cty.UnknownVal(cty.List(cty.String)),
"set": cty.UnknownVal(cty.Set(cty.Bool)),
"tuple": cty.UnknownVal(cty.Tuple([]cty.Type{cty.String, cty.Number})),
"map": cty.UnknownVal(cty.Map(cty.String)),
"object": cty.UnknownVal(cty.Object(map[string]cty.Type{"a": cty.String})),
}),
cty.ObjectVal(map[string]cty.Value{
"list": cty.EmptyTupleVal,
"set": cty.EmptyTupleVal,
"tuple": cty.EmptyTupleVal,
"map": cty.EmptyObjectVal,
"object": cty.EmptyObjectVal,
}),
},
}
for _, test := range tests {
got := sensitiveAsBool(test.Input)
if !reflect.DeepEqual(got, test.Want) {
t.Errorf(
"wrong result\ninput: %#v\ngot: %#v\nwant: %#v",
test.Input, got, test.Want,
)
}
}
}
func TestEncodePaths(t *testing.T) {
tests := map[string]struct {
Input cty.PathSet
Want json.RawMessage
}{
"empty set": {
cty.NewPathSet(),
json.RawMessage(nil),
},
"index path with string and int steps": {
cty.NewPathSet(cty.IndexStringPath("boop").IndexInt(0)),
json.RawMessage(`[["boop",0]]`),
},
"get attr path with one step": {
cty.NewPathSet(cty.GetAttrPath("triggers")),
json.RawMessage(`[["triggers"]]`),
},
"multiple paths of different types": {
cty.NewPathSet(
cty.GetAttrPath("alpha").GetAttr("beta").GetAttr("gamma"),
cty.GetAttrPath("triggers").IndexString("name"),
cty.IndexIntPath(0).IndexInt(1).IndexInt(2).IndexInt(3),
),
json.RawMessage(`[["alpha","beta","gamma"],["triggers","name"],[0,1,2,3]]`),
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
got, err := encodePaths(test.Input)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !cmp.Equal(got, test.Want) {
t.Errorf("wrong result:\n %v\n", cmp.Diff(got, test.Want))
}
})
}
}