github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/jsonplan/values_test.go (about)

     1  package jsonplan
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/hashicorp/terraform/internal/addrs"
     9  	"github.com/hashicorp/terraform/internal/configs/configschema"
    10  	"github.com/hashicorp/terraform/internal/plans"
    11  	"github.com/hashicorp/terraform/internal/terraform"
    12  	"github.com/zclconf/go-cty/cty"
    13  )
    14  
    15  func TestMarshalAttributeValues(t *testing.T) {
    16  	tests := []struct {
    17  		Attr   cty.Value
    18  		Schema *configschema.Block
    19  		Want   attributeValues
    20  	}{
    21  		{
    22  			cty.NilVal,
    23  			&configschema.Block{
    24  				Attributes: map[string]*configschema.Attribute{
    25  					"foo": {
    26  						Type:     cty.String,
    27  						Optional: true,
    28  					},
    29  				},
    30  			},
    31  			nil,
    32  		},
    33  		{
    34  			cty.NullVal(cty.String),
    35  			&configschema.Block{
    36  				Attributes: map[string]*configschema.Attribute{
    37  					"foo": {
    38  						Type:     cty.String,
    39  						Optional: true,
    40  					},
    41  				},
    42  			},
    43  			nil,
    44  		},
    45  		{
    46  			cty.ObjectVal(map[string]cty.Value{
    47  				"foo": cty.StringVal("bar"),
    48  			}),
    49  			&configschema.Block{
    50  				Attributes: map[string]*configschema.Attribute{
    51  					"foo": {
    52  						Type:     cty.String,
    53  						Optional: true,
    54  					},
    55  				},
    56  			},
    57  			attributeValues{"foo": json.RawMessage(`"bar"`)},
    58  		},
    59  		{
    60  			cty.ObjectVal(map[string]cty.Value{
    61  				"foo": cty.NullVal(cty.String),
    62  			}),
    63  			&configschema.Block{
    64  				Attributes: map[string]*configschema.Attribute{
    65  					"foo": {
    66  						Type:     cty.String,
    67  						Optional: true,
    68  					},
    69  				},
    70  			},
    71  			attributeValues{"foo": json.RawMessage(`null`)},
    72  		},
    73  		{
    74  			cty.ObjectVal(map[string]cty.Value{
    75  				"bar": cty.MapVal(map[string]cty.Value{
    76  					"hello": cty.StringVal("world"),
    77  				}),
    78  				"baz": cty.ListVal([]cty.Value{
    79  					cty.StringVal("goodnight"),
    80  					cty.StringVal("moon"),
    81  				}),
    82  			}),
    83  			&configschema.Block{
    84  				Attributes: map[string]*configschema.Attribute{
    85  					"bar": {
    86  						Type:     cty.Map(cty.String),
    87  						Required: true,
    88  					},
    89  					"baz": {
    90  						Type:     cty.List(cty.String),
    91  						Optional: true,
    92  					},
    93  				},
    94  			},
    95  			attributeValues{
    96  				"bar": json.RawMessage(`{"hello":"world"}`),
    97  				"baz": json.RawMessage(`["goodnight","moon"]`),
    98  			},
    99  		},
   100  	}
   101  
   102  	for _, test := range tests {
   103  		got := marshalAttributeValues(test.Attr, test.Schema)
   104  		eq := reflect.DeepEqual(got, test.Want)
   105  		if !eq {
   106  			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
   107  		}
   108  	}
   109  }
   110  
   111  func TestMarshalPlannedOutputs(t *testing.T) {
   112  	after, _ := plans.NewDynamicValue(cty.StringVal("after"), cty.DynamicPseudoType)
   113  
   114  	tests := []struct {
   115  		Changes *plans.Changes
   116  		Want    map[string]output
   117  		Err     bool
   118  	}{
   119  		{
   120  			&plans.Changes{},
   121  			nil,
   122  			false,
   123  		},
   124  		{
   125  			&plans.Changes{
   126  				Outputs: []*plans.OutputChangeSrc{
   127  					{
   128  						Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
   129  						ChangeSrc: plans.ChangeSrc{
   130  							Action: plans.Create,
   131  							After:  after,
   132  						},
   133  						Sensitive: false,
   134  					},
   135  				},
   136  			},
   137  			map[string]output{
   138  				"bar": {
   139  					Sensitive: false,
   140  					Type:      json.RawMessage(`"string"`),
   141  					Value:     json.RawMessage(`"after"`),
   142  				},
   143  			},
   144  			false,
   145  		},
   146  		{ // Delete action
   147  			&plans.Changes{
   148  				Outputs: []*plans.OutputChangeSrc{
   149  					{
   150  						Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
   151  						ChangeSrc: plans.ChangeSrc{
   152  							Action: plans.Delete,
   153  						},
   154  						Sensitive: false,
   155  					},
   156  				},
   157  			},
   158  			map[string]output{},
   159  			false,
   160  		},
   161  	}
   162  
   163  	for _, test := range tests {
   164  		got, err := marshalPlannedOutputs(test.Changes)
   165  		if test.Err {
   166  			if err == nil {
   167  				t.Fatal("succeeded; want error")
   168  			}
   169  			return
   170  		} else if err != nil {
   171  			t.Fatalf("unexpected error: %s", err)
   172  		}
   173  
   174  		eq := reflect.DeepEqual(got, test.Want)
   175  		if !eq {
   176  			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
   177  		}
   178  	}
   179  }
   180  
   181  func TestMarshalPlanResources(t *testing.T) {
   182  	tests := map[string]struct {
   183  		Action plans.Action
   184  		Before cty.Value
   185  		After  cty.Value
   186  		Want   []resource
   187  		Err    bool
   188  	}{
   189  		"create with unknowns": {
   190  			Action: plans.Create,
   191  			Before: cty.NullVal(cty.EmptyObject),
   192  			After: cty.ObjectVal(map[string]cty.Value{
   193  				"woozles": cty.UnknownVal(cty.String),
   194  				"foozles": cty.UnknownVal(cty.String),
   195  			}),
   196  			Want: []resource{{
   197  				Address:         "test_thing.example",
   198  				Mode:            "managed",
   199  				Type:            "test_thing",
   200  				Name:            "example",
   201  				Index:           addrs.InstanceKey(nil),
   202  				ProviderName:    "registry.terraform.io/hashicorp/test",
   203  				SchemaVersion:   1,
   204  				AttributeValues: attributeValues{},
   205  				SensitiveValues: json.RawMessage("{}"),
   206  			}},
   207  			Err: false,
   208  		},
   209  		"delete with null and nil": {
   210  			Action: plans.Delete,
   211  			Before: cty.NullVal(cty.EmptyObject),
   212  			After:  cty.NilVal,
   213  			Want:   nil,
   214  			Err:    false,
   215  		},
   216  		"delete": {
   217  			Action: plans.Delete,
   218  			Before: cty.ObjectVal(map[string]cty.Value{
   219  				"woozles": cty.StringVal("foo"),
   220  				"foozles": cty.StringVal("bar"),
   221  			}),
   222  			After: cty.NullVal(cty.Object(map[string]cty.Type{
   223  				"woozles": cty.String,
   224  				"foozles": cty.String,
   225  			})),
   226  			Want: nil,
   227  			Err:  false,
   228  		},
   229  		"update without unknowns": {
   230  			Action: plans.Update,
   231  			Before: cty.ObjectVal(map[string]cty.Value{
   232  				"woozles": cty.StringVal("foo"),
   233  				"foozles": cty.StringVal("bar"),
   234  			}),
   235  			After: cty.ObjectVal(map[string]cty.Value{
   236  				"woozles": cty.StringVal("baz"),
   237  				"foozles": cty.StringVal("bat"),
   238  			}),
   239  			Want: []resource{{
   240  				Address:       "test_thing.example",
   241  				Mode:          "managed",
   242  				Type:          "test_thing",
   243  				Name:          "example",
   244  				Index:         addrs.InstanceKey(nil),
   245  				ProviderName:  "registry.terraform.io/hashicorp/test",
   246  				SchemaVersion: 1,
   247  				AttributeValues: attributeValues{
   248  					"woozles": json.RawMessage(`"baz"`),
   249  					"foozles": json.RawMessage(`"bat"`),
   250  				},
   251  				SensitiveValues: json.RawMessage("{}"),
   252  			}},
   253  			Err: false,
   254  		},
   255  	}
   256  
   257  	for name, test := range tests {
   258  		t.Run(name, func(t *testing.T) {
   259  			before, err := plans.NewDynamicValue(test.Before, test.Before.Type())
   260  			if err != nil {
   261  				t.Fatal(err)
   262  			}
   263  
   264  			after, err := plans.NewDynamicValue(test.After, test.After.Type())
   265  			if err != nil {
   266  				t.Fatal(err)
   267  			}
   268  			testChange := &plans.Changes{
   269  				Resources: []*plans.ResourceInstanceChangeSrc{
   270  					{
   271  						Addr: addrs.Resource{
   272  							Mode: addrs.ManagedResourceMode,
   273  							Type: "test_thing",
   274  							Name: "example",
   275  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   276  						ProviderAddr: addrs.AbsProviderConfig{
   277  							Provider: addrs.NewDefaultProvider("test"),
   278  							Module:   addrs.RootModule,
   279  						},
   280  						ChangeSrc: plans.ChangeSrc{
   281  							Action: test.Action,
   282  							Before: before,
   283  							After:  after,
   284  						},
   285  					},
   286  				},
   287  			}
   288  
   289  			ris := testResourceAddrs()
   290  
   291  			got, err := marshalPlanResources(testChange, ris, testSchemas())
   292  			if test.Err {
   293  				if err == nil {
   294  					t.Fatal("succeeded; want error")
   295  				}
   296  				return
   297  			} else if err != nil {
   298  				t.Fatalf("unexpected error: %s", err)
   299  			}
   300  
   301  			eq := reflect.DeepEqual(got, test.Want)
   302  			if !eq {
   303  				t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
   304  			}
   305  		})
   306  	}
   307  }
   308  
   309  func TestMarshalPlanValuesNoopDeposed(t *testing.T) {
   310  	dynamicNull, err := plans.NewDynamicValue(cty.NullVal(cty.DynamicPseudoType), cty.DynamicPseudoType)
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  	testChange := &plans.Changes{
   315  		Resources: []*plans.ResourceInstanceChangeSrc{
   316  			{
   317  				Addr: addrs.Resource{
   318  					Mode: addrs.ManagedResourceMode,
   319  					Type: "test_thing",
   320  					Name: "example",
   321  				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   322  				DeposedKey: "12345678",
   323  				ProviderAddr: addrs.AbsProviderConfig{
   324  					Provider: addrs.NewDefaultProvider("test"),
   325  					Module:   addrs.RootModule,
   326  				},
   327  				ChangeSrc: plans.ChangeSrc{
   328  					Action: plans.NoOp,
   329  					Before: dynamicNull,
   330  					After:  dynamicNull,
   331  				},
   332  			},
   333  		},
   334  	}
   335  
   336  	_, err = marshalPlannedValues(testChange, testSchemas())
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	}
   340  }
   341  
   342  func testSchemas() *terraform.Schemas {
   343  	return &terraform.Schemas{
   344  		Providers: map[addrs.Provider]*terraform.ProviderSchema{
   345  			addrs.NewDefaultProvider("test"): &terraform.ProviderSchema{
   346  				ResourceTypes: map[string]*configschema.Block{
   347  					"test_thing": {
   348  						Attributes: map[string]*configschema.Attribute{
   349  							"woozles": {Type: cty.String, Optional: true, Computed: true},
   350  							"foozles": {Type: cty.String, Optional: true},
   351  						},
   352  					},
   353  				},
   354  				ResourceTypeSchemaVersions: map[string]uint64{
   355  					"test_thing": 1,
   356  				},
   357  			},
   358  		},
   359  	}
   360  }
   361  
   362  func testResourceAddrs() []addrs.AbsResourceInstance {
   363  	return []addrs.AbsResourceInstance{
   364  		mustAddr("test_thing.example"),
   365  	}
   366  }
   367  
   368  func mustAddr(str string) addrs.AbsResourceInstance {
   369  	addr, diags := addrs.ParseAbsResourceInstanceStr(str)
   370  	if diags.HasErrors() {
   371  		panic(diags.Err())
   372  	}
   373  	return addr
   374  }