github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/views/json/output_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package json
     5  
     6  import (
     7  	"encoding/json"
     8  	"testing"
     9  
    10  	"github.com/google/go-cmp/cmp"
    11  	"github.com/terramate-io/tf/addrs"
    12  	"github.com/terramate-io/tf/lang/marks"
    13  	"github.com/terramate-io/tf/plans"
    14  	"github.com/terramate-io/tf/states"
    15  	"github.com/zclconf/go-cty/cty"
    16  )
    17  
    18  func TestOutputsFromMap(t *testing.T) {
    19  	got, diags := OutputsFromMap(map[string]*states.OutputValue{
    20  		// Normal non-sensitive output
    21  		"boop": {
    22  			Value: cty.NumberIntVal(1234),
    23  		},
    24  		// Sensitive string output
    25  		"beep": {
    26  			Value:     cty.StringVal("horse-battery").Mark(marks.Sensitive),
    27  			Sensitive: true,
    28  		},
    29  		// Sensitive object output which is marked at the leaf
    30  		"blorp": {
    31  			Value: cty.ObjectVal(map[string]cty.Value{
    32  				"a": cty.ObjectVal(map[string]cty.Value{
    33  					"b": cty.ObjectVal(map[string]cty.Value{
    34  						"c": cty.StringVal("oh, hi").Mark(marks.Sensitive),
    35  					}),
    36  				}),
    37  			}),
    38  			Sensitive: true,
    39  		},
    40  		// Null value
    41  		"honk": {
    42  			Value: cty.NullVal(cty.Map(cty.Bool)),
    43  		},
    44  	})
    45  	if len(diags) > 0 {
    46  		t.Fatal(diags.Err())
    47  	}
    48  
    49  	want := Outputs{
    50  		"boop": {
    51  			Sensitive: false,
    52  			Type:      json.RawMessage(`"number"`),
    53  			Value:     json.RawMessage(`1234`),
    54  		},
    55  		"beep": {
    56  			Sensitive: true,
    57  			Type:      json.RawMessage(`"string"`),
    58  		},
    59  		"blorp": {
    60  			Sensitive: true,
    61  			Type:      json.RawMessage(`["object",{"a":["object",{"b":["object",{"c":"string"}]}]}]`),
    62  		},
    63  		"honk": {
    64  			Sensitive: false,
    65  			Type:      json.RawMessage(`["map","bool"]`),
    66  			Value:     json.RawMessage(`null`),
    67  		},
    68  	}
    69  
    70  	if !cmp.Equal(want, got) {
    71  		t.Fatalf("unexpected result\n%s", cmp.Diff(want, got))
    72  	}
    73  }
    74  
    75  func TestOutputsFromChanges(t *testing.T) {
    76  	root := addrs.RootModuleInstance
    77  	num, err := plans.NewDynamicValue(cty.NumberIntVal(1234), cty.Number)
    78  	if err != nil {
    79  		t.Fatalf("unexpected error creating dynamic value: %v", err)
    80  	}
    81  	str, err := plans.NewDynamicValue(cty.StringVal("1234"), cty.String)
    82  	if err != nil {
    83  		t.Fatalf("unexpected error creating dynamic value: %v", err)
    84  	}
    85  
    86  	got := OutputsFromChanges([]*plans.OutputChangeSrc{
    87  		// Unchanged output "boop", value 1234
    88  		{
    89  			Addr: root.OutputValue("boop"),
    90  			ChangeSrc: plans.ChangeSrc{
    91  				Action: plans.NoOp,
    92  				Before: num,
    93  				After:  num,
    94  			},
    95  			Sensitive: false,
    96  		},
    97  		// New output "beep", value 1234
    98  		{
    99  			Addr: root.OutputValue("beep"),
   100  			ChangeSrc: plans.ChangeSrc{
   101  				Action: plans.Create,
   102  				Before: nil,
   103  				After:  num,
   104  			},
   105  			Sensitive: false,
   106  		},
   107  		// Deleted output "blorp", prior value 1234
   108  		{
   109  			Addr: root.OutputValue("blorp"),
   110  			ChangeSrc: plans.ChangeSrc{
   111  				Action: plans.Delete,
   112  				Before: num,
   113  				After:  nil,
   114  			},
   115  			Sensitive: false,
   116  		},
   117  		// Updated output "honk", prior value 1234, new value "1234"
   118  		{
   119  			Addr: root.OutputValue("honk"),
   120  			ChangeSrc: plans.ChangeSrc{
   121  				Action: plans.Update,
   122  				Before: num,
   123  				After:  str,
   124  			},
   125  			Sensitive: false,
   126  		},
   127  		// New sensitive output "secret", value "1234"
   128  		{
   129  			Addr: root.OutputValue("secret"),
   130  			ChangeSrc: plans.ChangeSrc{
   131  				Action: plans.Create,
   132  				Before: nil,
   133  				After:  str,
   134  			},
   135  			Sensitive: true,
   136  		},
   137  	})
   138  
   139  	want := Outputs{
   140  		"boop": {
   141  			Action:    "noop",
   142  			Sensitive: false,
   143  		},
   144  		"beep": {
   145  			Action:    "create",
   146  			Sensitive: false,
   147  		},
   148  		"blorp": {
   149  			Action:    "delete",
   150  			Sensitive: false,
   151  		},
   152  		"honk": {
   153  			Action:    "update",
   154  			Sensitive: false,
   155  		},
   156  		"secret": {
   157  			Action:    "create",
   158  			Sensitive: true,
   159  		},
   160  	}
   161  
   162  	if !cmp.Equal(want, got) {
   163  		t.Fatalf("unexpected result\n%s", cmp.Diff(want, got))
   164  	}
   165  }
   166  
   167  func TestOutputs_String(t *testing.T) {
   168  	outputs := Outputs{
   169  		"boop": {
   170  			Sensitive: false,
   171  			Type:      json.RawMessage(`"number"`),
   172  			Value:     json.RawMessage(`1234`),
   173  		},
   174  		"beep": {
   175  			Sensitive: true,
   176  			Type:      json.RawMessage(`"string"`),
   177  			Value:     json.RawMessage(`"horse-battery"`),
   178  		},
   179  	}
   180  	if got, want := outputs.String(), "Outputs: 2"; got != want {
   181  		t.Fatalf("unexpected value\n got: %q\nwant: %q", got, want)
   182  	}
   183  }