github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/node_output_test.go (about) 1 package terraform 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/hashicorp/hcl/v2" 8 "github.com/zclconf/go-cty/cty" 9 10 "github.com/hashicorp/terraform/internal/addrs" 11 "github.com/hashicorp/terraform/internal/checks" 12 "github.com/hashicorp/terraform/internal/configs" 13 "github.com/hashicorp/terraform/internal/lang/marks" 14 "github.com/hashicorp/terraform/internal/states" 15 ) 16 17 func TestNodeApplyableOutputExecute_knownValue(t *testing.T) { 18 ctx := new(MockEvalContext) 19 ctx.StateState = states.NewState().SyncWrapper() 20 ctx.RefreshStateState = states.NewState().SyncWrapper() 21 ctx.ChecksState = checks.NewState(nil) 22 23 config := &configs.Output{Name: "map-output"} 24 addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) 25 node := &NodeApplyableOutput{Config: config, Addr: addr} 26 val := cty.MapVal(map[string]cty.Value{ 27 "a": cty.StringVal("b"), 28 }) 29 ctx.EvaluateExprResult = val 30 31 err := node.Execute(ctx, walkApply) 32 if err != nil { 33 t.Fatalf("unexpected execute error: %s", err) 34 } 35 36 outputVal := ctx.StateState.OutputValue(addr) 37 if got, want := outputVal.Value, val; !got.RawEquals(want) { 38 t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want) 39 } 40 41 if !ctx.RefreshStateCalled { 42 t.Fatal("should have called RefreshState, but didn't") 43 } 44 refreshOutputVal := ctx.RefreshStateState.OutputValue(addr) 45 if got, want := refreshOutputVal.Value, val; !got.RawEquals(want) { 46 t.Fatalf("wrong output value in refresh state\n got: %#v\nwant: %#v", got, want) 47 } 48 } 49 50 func TestNodeApplyableOutputExecute_noState(t *testing.T) { 51 ctx := new(MockEvalContext) 52 53 config := &configs.Output{Name: "map-output"} 54 addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) 55 node := &NodeApplyableOutput{Config: config, Addr: addr} 56 val := cty.MapVal(map[string]cty.Value{ 57 "a": cty.StringVal("b"), 58 }) 59 ctx.EvaluateExprResult = val 60 61 err := node.Execute(ctx, walkApply) 62 if err != nil { 63 t.Fatalf("unexpected execute error: %s", err) 64 } 65 } 66 67 func TestNodeApplyableOutputExecute_invalidDependsOn(t *testing.T) { 68 ctx := new(MockEvalContext) 69 ctx.StateState = states.NewState().SyncWrapper() 70 ctx.ChecksState = checks.NewState(nil) 71 72 config := &configs.Output{ 73 Name: "map-output", 74 DependsOn: []hcl.Traversal{ 75 { 76 hcl.TraverseRoot{Name: "test_instance"}, 77 hcl.TraverseAttr{Name: "foo"}, 78 hcl.TraverseAttr{Name: "bar"}, 79 }, 80 }, 81 } 82 addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) 83 node := &NodeApplyableOutput{Config: config, Addr: addr} 84 val := cty.MapVal(map[string]cty.Value{ 85 "a": cty.StringVal("b"), 86 }) 87 ctx.EvaluateExprResult = val 88 89 diags := node.Execute(ctx, walkApply) 90 if !diags.HasErrors() { 91 t.Fatal("expected execute error, but there was none") 92 } 93 if got, want := diags.Err().Error(), "Invalid depends_on reference"; !strings.Contains(got, want) { 94 t.Errorf("expected error to include %q, but was: %s", want, got) 95 } 96 } 97 98 func TestNodeApplyableOutputExecute_sensitiveValueNotOutput(t *testing.T) { 99 ctx := new(MockEvalContext) 100 ctx.StateState = states.NewState().SyncWrapper() 101 ctx.ChecksState = checks.NewState(nil) 102 103 config := &configs.Output{Name: "map-output"} 104 addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) 105 node := &NodeApplyableOutput{Config: config, Addr: addr} 106 val := cty.MapVal(map[string]cty.Value{ 107 "a": cty.StringVal("b").Mark(marks.Sensitive), 108 }) 109 ctx.EvaluateExprResult = val 110 111 diags := node.Execute(ctx, walkApply) 112 if !diags.HasErrors() { 113 t.Fatal("expected execute error, but there was none") 114 } 115 if got, want := diags.Err().Error(), "Output refers to sensitive values"; !strings.Contains(got, want) { 116 t.Errorf("expected error to include %q, but was: %s", want, got) 117 } 118 } 119 120 func TestNodeApplyableOutputExecute_sensitiveValueAndOutput(t *testing.T) { 121 ctx := new(MockEvalContext) 122 ctx.StateState = states.NewState().SyncWrapper() 123 ctx.ChecksState = checks.NewState(nil) 124 125 config := &configs.Output{ 126 Name: "map-output", 127 Sensitive: true, 128 } 129 addr := addrs.OutputValue{Name: config.Name}.Absolute(addrs.RootModuleInstance) 130 node := &NodeApplyableOutput{Config: config, Addr: addr} 131 val := cty.MapVal(map[string]cty.Value{ 132 "a": cty.StringVal("b").Mark(marks.Sensitive), 133 }) 134 ctx.EvaluateExprResult = val 135 136 err := node.Execute(ctx, walkApply) 137 if err != nil { 138 t.Fatalf("unexpected execute error: %s", err) 139 } 140 141 // Unmarked value should be stored in state 142 outputVal := ctx.StateState.OutputValue(addr) 143 want, _ := val.UnmarkDeep() 144 if got := outputVal.Value; !got.RawEquals(want) { 145 t.Errorf("wrong output value in state\n got: %#v\nwant: %#v", got, want) 146 } 147 } 148 149 func TestNodeDestroyableOutputExecute(t *testing.T) { 150 outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance) 151 152 state := states.NewState() 153 state.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false) 154 state.OutputValue(outputAddr) 155 156 ctx := &MockEvalContext{ 157 StateState: state.SyncWrapper(), 158 } 159 node := NodeDestroyableOutput{Addr: outputAddr} 160 161 diags := node.Execute(ctx, walkApply) 162 if diags.HasErrors() { 163 t.Fatalf("Unexpected error: %s", diags.Err()) 164 } 165 if state.OutputValue(outputAddr) != nil { 166 t.Fatal("Unexpected outputs in state after removal") 167 } 168 } 169 170 func TestNodeDestroyableOutputExecute_notInState(t *testing.T) { 171 outputAddr := addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance) 172 173 state := states.NewState() 174 175 ctx := &MockEvalContext{ 176 StateState: state.SyncWrapper(), 177 } 178 node := NodeDestroyableOutput{Addr: outputAddr} 179 180 diags := node.Execute(ctx, walkApply) 181 if diags.HasErrors() { 182 t.Fatalf("Unexpected error: %s", diags.Err()) 183 } 184 if state.OutputValue(outputAddr) != nil { 185 t.Fatal("Unexpected outputs in state after removal") 186 } 187 }