kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/terraform/node_output_test.go (about)

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