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