mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
27a794062e
* command: refactor testBackendState to write states.State testBackendState was using the older terraform.State format, which is no longer sufficient for most tests since the state upgrader does not encode provider FQNs automatically. Users will run `terraform 0.13upgrade` to update their state to include provider FQNs in resources, but tests need to use the modern state format instead of relying on the automatic upgrade. * plan tests passing * graph tests passing * json packages test update * command test updates * update show test fixtures * state show tests passing
327 lines
7.3 KiB
Go
327 lines
7.3 KiB
Go
package jsonplan
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
"github.com/hashicorp/terraform/plans"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestMarshalAttributeValues(t *testing.T) {
|
|
tests := []struct {
|
|
Attr cty.Value
|
|
Schema *configschema.Block
|
|
Want attributeValues
|
|
}{
|
|
{
|
|
cty.NilVal,
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
cty.NullVal(cty.String),
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.StringVal("bar"),
|
|
}),
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
attributeValues{"foo": json.RawMessage(`"bar"`)},
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"foo": cty.NullVal(cty.String),
|
|
}),
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"foo": {
|
|
Type: cty.String,
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
attributeValues{"foo": json.RawMessage(`null`)},
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.MapVal(map[string]cty.Value{
|
|
"hello": cty.StringVal("world"),
|
|
}),
|
|
"baz": cty.ListVal([]cty.Value{
|
|
cty.StringVal("goodnight"),
|
|
cty.StringVal("moon"),
|
|
}),
|
|
}),
|
|
&configschema.Block{
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"bar": {
|
|
Type: cty.Map(cty.String),
|
|
Required: true,
|
|
},
|
|
"baz": {
|
|
Type: cty.List(cty.String),
|
|
Optional: true,
|
|
},
|
|
},
|
|
},
|
|
attributeValues{
|
|
"bar": json.RawMessage(`{"hello":"world"}`),
|
|
"baz": json.RawMessage(`["goodnight","moon"]`),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
got := marshalAttributeValues(test.Attr, test.Schema)
|
|
eq := reflect.DeepEqual(got, test.Want)
|
|
if !eq {
|
|
t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalPlannedOutputs(t *testing.T) {
|
|
after, _ := plans.NewDynamicValue(cty.StringVal("after"), cty.DynamicPseudoType)
|
|
|
|
tests := []struct {
|
|
Changes *plans.Changes
|
|
Want map[string]output
|
|
Err bool
|
|
}{
|
|
{
|
|
&plans.Changes{},
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
&plans.Changes{
|
|
Outputs: []*plans.OutputChangeSrc{
|
|
{
|
|
Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
|
|
ChangeSrc: plans.ChangeSrc{
|
|
Action: plans.Create,
|
|
After: after,
|
|
},
|
|
Sensitive: false,
|
|
},
|
|
},
|
|
},
|
|
map[string]output{
|
|
"bar": {
|
|
Sensitive: false,
|
|
Value: json.RawMessage(`"after"`),
|
|
},
|
|
},
|
|
false,
|
|
},
|
|
{ // Delete action
|
|
&plans.Changes{
|
|
Outputs: []*plans.OutputChangeSrc{
|
|
{
|
|
Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
|
|
ChangeSrc: plans.ChangeSrc{
|
|
Action: plans.Delete,
|
|
},
|
|
Sensitive: false,
|
|
},
|
|
},
|
|
},
|
|
map[string]output{},
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
got, err := marshalPlannedOutputs(test.Changes)
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
return
|
|
} else if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
eq := reflect.DeepEqual(got, test.Want)
|
|
if !eq {
|
|
t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMarshalPlanResources(t *testing.T) {
|
|
tests := map[string]struct {
|
|
Action plans.Action
|
|
Before cty.Value
|
|
After cty.Value
|
|
Want []resource
|
|
Err bool
|
|
}{
|
|
"create with unknowns": {
|
|
Action: plans.Create,
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
"woozles": cty.UnknownVal(cty.String),
|
|
"foozles": cty.UnknownVal(cty.String),
|
|
}),
|
|
Want: []resource{resource{
|
|
Address: "test_thing.example",
|
|
Mode: "managed",
|
|
Type: "test_thing",
|
|
Name: "example",
|
|
Index: addrs.InstanceKey(nil),
|
|
ProviderName: "registry.terraform.io/hashicorp/test",
|
|
SchemaVersion: 1,
|
|
AttributeValues: attributeValues{},
|
|
}},
|
|
Err: false,
|
|
},
|
|
"delete": {
|
|
Action: plans.Delete,
|
|
Before: cty.NullVal(cty.EmptyObject),
|
|
After: cty.NilVal,
|
|
Want: nil,
|
|
Err: false,
|
|
},
|
|
"update without unknowns": {
|
|
Action: plans.Update,
|
|
Before: cty.ObjectVal(map[string]cty.Value{
|
|
"woozles": cty.StringVal("foo"),
|
|
"foozles": cty.StringVal("bar"),
|
|
}),
|
|
After: cty.ObjectVal(map[string]cty.Value{
|
|
"woozles": cty.StringVal("baz"),
|
|
"foozles": cty.StringVal("bat"),
|
|
}),
|
|
Want: []resource{resource{
|
|
Address: "test_thing.example",
|
|
Mode: "managed",
|
|
Type: "test_thing",
|
|
Name: "example",
|
|
Index: addrs.InstanceKey(nil),
|
|
ProviderName: "registry.terraform.io/hashicorp/test",
|
|
SchemaVersion: 1,
|
|
AttributeValues: attributeValues{
|
|
|
|
"woozles": json.RawMessage(`"baz"`),
|
|
"foozles": json.RawMessage(`"bat"`),
|
|
},
|
|
}},
|
|
Err: false,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
before, err := plans.NewDynamicValue(test.Before, test.Before.Type())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
after, err := plans.NewDynamicValue(test.After, test.After.Type())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testChange := &plans.Changes{
|
|
Resources: []*plans.ResourceInstanceChangeSrc{
|
|
{
|
|
Addr: addrs.Resource{
|
|
Mode: addrs.ManagedResourceMode,
|
|
Type: "test_thing",
|
|
Name: "example",
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
ProviderAddr: addrs.AbsProviderConfig{
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
Module: addrs.RootModule,
|
|
},
|
|
ChangeSrc: plans.ChangeSrc{
|
|
Action: test.Action,
|
|
Before: before,
|
|
After: after,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ris := testResourceAddrs()
|
|
|
|
got, err := marshalPlanResources(testChange, ris, testSchemas())
|
|
if test.Err {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
return
|
|
} else if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
eq := reflect.DeepEqual(got, test.Want)
|
|
if !eq {
|
|
t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func testSchemas() *terraform.Schemas {
|
|
return &terraform.Schemas{
|
|
Providers: map[addrs.Provider]*terraform.ProviderSchema{
|
|
addrs.NewDefaultProvider("test"): &terraform.ProviderSchema{
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
"test_thing": {
|
|
Attributes: map[string]*configschema.Attribute{
|
|
"woozles": {Type: cty.String, Optional: true, Computed: true},
|
|
"foozles": {Type: cty.String, Optional: true},
|
|
},
|
|
},
|
|
},
|
|
ResourceTypeSchemaVersions: map[string]uint64{
|
|
"test_thing": 1,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func testResourceAddrs() []addrs.AbsResourceInstance {
|
|
return []addrs.AbsResourceInstance{
|
|
mustAddr("test_thing.example"),
|
|
}
|
|
}
|
|
|
|
func mustAddr(str string) addrs.AbsResourceInstance {
|
|
addr, diags := addrs.ParseAbsResourceInstanceStr(str)
|
|
if diags.HasErrors() {
|
|
panic(diags.Err())
|
|
}
|
|
return addr
|
|
}
|