github.com/opentofu/opentofu@v1.7.1/internal/plans/changes_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package plans
     7  
     8  import (
     9  	"fmt"
    10  	"testing"
    11  
    12  	"github.com/opentofu/opentofu/internal/addrs"
    13  	"github.com/opentofu/opentofu/internal/lang/marks"
    14  	"github.com/zclconf/go-cty/cty"
    15  )
    16  
    17  func TestChangesEmpty(t *testing.T) {
    18  	testCases := map[string]struct {
    19  		changes *Changes
    20  		want    bool
    21  	}{
    22  		"no changes": {
    23  			&Changes{},
    24  			true,
    25  		},
    26  		"resource change": {
    27  			&Changes{
    28  				Resources: []*ResourceInstanceChangeSrc{
    29  					{
    30  						Addr: addrs.Resource{
    31  							Mode: addrs.ManagedResourceMode,
    32  							Type: "test_thing",
    33  							Name: "woot",
    34  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    35  						PrevRunAddr: addrs.Resource{
    36  							Mode: addrs.ManagedResourceMode,
    37  							Type: "test_thing",
    38  							Name: "woot",
    39  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    40  						ChangeSrc: ChangeSrc{
    41  							Action: Update,
    42  						},
    43  					},
    44  				},
    45  			},
    46  			false,
    47  		},
    48  		"resource change with no-op action": {
    49  			&Changes{
    50  				Resources: []*ResourceInstanceChangeSrc{
    51  					{
    52  						Addr: addrs.Resource{
    53  							Mode: addrs.ManagedResourceMode,
    54  							Type: "test_thing",
    55  							Name: "woot",
    56  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    57  						PrevRunAddr: addrs.Resource{
    58  							Mode: addrs.ManagedResourceMode,
    59  							Type: "test_thing",
    60  							Name: "woot",
    61  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    62  						ChangeSrc: ChangeSrc{
    63  							Action: NoOp,
    64  						},
    65  					},
    66  				},
    67  			},
    68  			true,
    69  		},
    70  		"resource moved with no-op change": {
    71  			&Changes{
    72  				Resources: []*ResourceInstanceChangeSrc{
    73  					{
    74  						Addr: addrs.Resource{
    75  							Mode: addrs.ManagedResourceMode,
    76  							Type: "test_thing",
    77  							Name: "woot",
    78  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    79  						PrevRunAddr: addrs.Resource{
    80  							Mode: addrs.ManagedResourceMode,
    81  							Type: "test_thing",
    82  							Name: "toot",
    83  						}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    84  						ChangeSrc: ChangeSrc{
    85  							Action: NoOp,
    86  						},
    87  					},
    88  				},
    89  			},
    90  			false,
    91  		},
    92  		"output change": {
    93  			&Changes{
    94  				Outputs: []*OutputChangeSrc{
    95  					{
    96  						Addr: addrs.OutputValue{
    97  							Name: "result",
    98  						}.Absolute(addrs.RootModuleInstance),
    99  						ChangeSrc: ChangeSrc{
   100  							Action: Update,
   101  						},
   102  					},
   103  				},
   104  			},
   105  			false,
   106  		},
   107  		"output change no-op": {
   108  			&Changes{
   109  				Outputs: []*OutputChangeSrc{
   110  					{
   111  						Addr: addrs.OutputValue{
   112  							Name: "result",
   113  						}.Absolute(addrs.RootModuleInstance),
   114  						ChangeSrc: ChangeSrc{
   115  							Action: NoOp,
   116  						},
   117  					},
   118  				},
   119  			},
   120  			true,
   121  		},
   122  	}
   123  
   124  	for name, tc := range testCases {
   125  		t.Run(name, func(t *testing.T) {
   126  			if got, want := tc.changes.Empty(), tc.want; got != want {
   127  				t.Fatalf("unexpected result: got %v, want %v", got, want)
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestChangeEncodeSensitive(t *testing.T) {
   134  	testVals := []cty.Value{
   135  		cty.ObjectVal(map[string]cty.Value{
   136  			"ding": cty.StringVal("dong").Mark(marks.Sensitive),
   137  		}),
   138  		cty.StringVal("bleep").Mark("bloop"),
   139  		cty.ListVal([]cty.Value{cty.UnknownVal(cty.String).Mark("sup?")}),
   140  	}
   141  
   142  	for _, v := range testVals {
   143  		t.Run(fmt.Sprintf("%#v", v), func(t *testing.T) {
   144  			change := Change{
   145  				Before: cty.NullVal(v.Type()),
   146  				After:  v,
   147  			}
   148  
   149  			encoded, err := change.Encode(v.Type())
   150  			if err != nil {
   151  				t.Fatal(err)
   152  			}
   153  
   154  			decoded, err := encoded.Decode(v.Type())
   155  			if err != nil {
   156  				t.Fatal(err)
   157  			}
   158  
   159  			if !v.RawEquals(decoded.After) {
   160  				t.Fatalf("%#v != %#v\n", decoded.After, v)
   161  			}
   162  		})
   163  	}
   164  }