github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/command/jsonplan/values_test.go (about)

     1  package jsonplan
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/muratcelep/terraform/not-internal/addrs"
     9  	"github.com/muratcelep/terraform/not-internal/configs/configschema"
    10  	"github.com/muratcelep/terraform/not-internal/plans"
    11  	"github.com/muratcelep/terraform/not-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  					Value:     json.RawMessage(`"after"`),
   141  				},
   142  			},
   143  			false,
   144  		},
   145  		{ // Delete action
   146  			&plans.Changes{
   147  				Outputs: []*plans.OutputChangeSrc{
   148  					{
   149  						Addr: addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
   150  						ChangeSrc: plans.ChangeSrc{
   151  							Action: plans.Delete,
   152  						},
   153  						Sensitive: false,
   154  					},
   155  				},
   156  			},
   157  			map[string]output{},
   158  			false,
   159  		},
   160  	}
   161  
   162  	for _, test := range tests {
   163  		got, err := marshalPlannedOutputs(test.Changes)
   164  		if test.Err {
   165  			if err == nil {
   166  				t.Fatal("succeeded; want error")
   167  			}
   168  			return
   169  		} else if err != nil {
   170  			t.Fatalf("unexpected error: %s", err)
   171  		}
   172  
   173  		eq := reflect.DeepEqual(got, test.Want)
   174  		if !eq {
   175  			t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
   176  		}
   177  	}
   178  }
   179  
   180  func TestMarshalPlanResources(t *testing.T) {
   181  	tests := map[string]struct {
   182  		Action plans.Action
   183  		Before cty.Value
   184  		After  cty.Value
   185  		Want   []resource
   186  		Err    bool
   187  	}{
   188  		"create with unknowns": {
   189  			Action: plans.Create,
   190  			Before: cty.NullVal(cty.EmptyObject),
   191  			After: cty.ObjectVal(map[string]cty.Value{
   192  				"woozles": cty.UnknownVal(cty.String),
   193  				"foozles": cty.UnknownVal(cty.String),
   194  			}),
   195  			Want: []resource{{
   196  				Address:         "test_thing.example",
   197  				Mode:            "managed",
   198  				Type:            "test_thing",
   199  				Name:            "example",
   200  				Index:           addrs.InstanceKey(nil),
   201  				ProviderName:    "registry.terraform.io/hashicorp/test",
   202  				SchemaVersion:   1,
   203  				AttributeValues: attributeValues{},
   204  				SensitiveValues: json.RawMessage("{}"),
   205  			}},
   206  			Err: false,
   207  		},
   208  		"delete with null and nil": {
   209  			Action: plans.Delete,
   210  			Before: cty.NullVal(cty.EmptyObject),
   211  			After:  cty.NilVal,
   212  			Want:   nil,
   213  			Err:    false,
   214  		},
   215  		"delete": {
   216  			Action: plans.Delete,
   217  			Before: cty.ObjectVal(map[string]cty.Value{
   218  				"woozles": cty.StringVal("foo"),
   219  				"foozles": cty.StringVal("bar"),
   220  			}),
   221  			After: cty.NullVal(cty.Object(map[string]cty.Type{
   222  				"woozles": cty.String,
   223  				"foozles": cty.String,
   224  			})),
   225  			Want: nil,
   226  			Err:  false,
   227  		},
   228  		"update without unknowns": {
   229  			Action: plans.Update,
   230  			Before: cty.ObjectVal(map[string]cty.Value{
   231  				"woozles": cty.StringVal("foo"),
   232  				"foozles": cty.StringVal("bar"),
   233  			}),
   234  			After: cty.ObjectVal(map[string]cty.Value{
   235  				"woozles": cty.StringVal("baz"),
   236  				"foozles": cty.StringVal("bat"),
   237  			}),
   238  			Want: []resource{{
   239  				Address:       "test_thing.example",
   240  				Mode:          "managed",
   241  				Type:          "test_thing",
   242  				Name:          "example",
   243  				Index:         addrs.InstanceKey(nil),
   244  				ProviderName:  "registry.terraform.io/hashicorp/test",
   245  				SchemaVersion: 1,
   246  				AttributeValues: attributeValues{
   247  					"woozles": json.RawMessage(`"baz"`),
   248  					"foozles": json.RawMessage(`"bat"`),
   249  				},
   250  				SensitiveValues: json.RawMessage("{}"),
   251  			}},
   252  			Err: false,
   253  		},
   254  	}
   255  
   256  	for name, test := range tests {
   257  		t.Run(name, func(t *testing.T) {
   258  			before, err := plans.NewDynamicValue(test.Before, test.Before.Type())
   259  			if err != nil {
   260  				t.Fatal(err)
   261  			}
   262  
   263  			after, err := plans.NewDynamicValue(test.After, test.After.Type())
   264  			if err != nil {
   265  				t.Fatal(err)
   266  			}
   267  			testChange := &plans.Changes{
   268  				Resources: []*plans.ResourceInstanceChangeSrc{
   269  					{
   270  						Addr: addrs.Resource{
   271  							Mode: addrs.ManagedResourceMode,
   272  							Type: "test_thing",
   273  							Name: "example",
   274  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   275  						ProviderAddr: addrs.AbsProviderConfig{
   276  							Provider: addrs.NewDefaultProvider("test"),
   277  							Module:   addrs.RootModule,
   278  						},
   279  						ChangeSrc: plans.ChangeSrc{
   280  							Action: test.Action,
   281  							Before: before,
   282  							After:  after,
   283  						},
   284  					},
   285  				},
   286  			}
   287  
   288  			ris := testResourceAddrs()
   289  
   290  			got, err := marshalPlanResources(testChange, ris, testSchemas())
   291  			if test.Err {
   292  				if err == nil {
   293  					t.Fatal("succeeded; want error")
   294  				}
   295  				return
   296  			} else if err != nil {
   297  				t.Fatalf("unexpected error: %s", err)
   298  			}
   299  
   300  			eq := reflect.DeepEqual(got, test.Want)
   301  			if !eq {
   302  				t.Fatalf("wrong result:\nGot: %#v\nWant: %#v\n", got, test.Want)
   303  			}
   304  		})
   305  	}
   306  }
   307  
   308  func TestMarshalPlanValuesNoopDeposed(t *testing.T) {
   309  	dynamicNull, err := plans.NewDynamicValue(cty.NullVal(cty.DynamicPseudoType), cty.DynamicPseudoType)
   310  	if err != nil {
   311  		t.Fatal(err)
   312  	}
   313  	testChange := &plans.Changes{
   314  		Resources: []*plans.ResourceInstanceChangeSrc{
   315  			{
   316  				Addr: addrs.Resource{
   317  					Mode: addrs.ManagedResourceMode,
   318  					Type: "test_thing",
   319  					Name: "example",
   320  				}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   321  				DeposedKey: "12345678",
   322  				ProviderAddr: addrs.AbsProviderConfig{
   323  					Provider: addrs.NewDefaultProvider("test"),
   324  					Module:   addrs.RootModule,
   325  				},
   326  				ChangeSrc: plans.ChangeSrc{
   327  					Action: plans.NoOp,
   328  					Before: dynamicNull,
   329  					After:  dynamicNull,
   330  				},
   331  			},
   332  		},
   333  	}
   334  
   335  	_, err = marshalPlannedValues(testChange, testSchemas())
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  }
   340  
   341  func testSchemas() *terraform.Schemas {
   342  	return &terraform.Schemas{
   343  		Providers: map[addrs.Provider]*terraform.ProviderSchema{
   344  			addrs.NewDefaultProvider("test"): &terraform.ProviderSchema{
   345  				ResourceTypes: map[string]*configschema.Block{
   346  					"test_thing": {
   347  						Attributes: map[string]*configschema.Attribute{
   348  							"woozles": {Type: cty.String, Optional: true, Computed: true},
   349  							"foozles": {Type: cty.String, Optional: true},
   350  						},
   351  					},
   352  				},
   353  				ResourceTypeSchemaVersions: map[string]uint64{
   354  					"test_thing": 1,
   355  				},
   356  			},
   357  		},
   358  	}
   359  }
   360  
   361  func testResourceAddrs() []addrs.AbsResourceInstance {
   362  	return []addrs.AbsResourceInstance{
   363  		mustAddr("test_thing.example"),
   364  	}
   365  }
   366  
   367  func mustAddr(str string) addrs.AbsResourceInstance {
   368  	addr, diags := addrs.ParseAbsResourceInstanceStr(str)
   369  	if diags.HasErrors() {
   370  		panic(diags.Err())
   371  	}
   372  	return addr
   373  }