github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/providers/terraform/data_source_state_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hashicorp/terraform/tfdiags"
     7  
     8  	"github.com/apparentlymart/go-dump/dump"
     9  	"github.com/hashicorp/terraform/backend"
    10  	"github.com/zclconf/go-cty/cty"
    11  )
    12  
    13  func TestResource(t *testing.T) {
    14  	if err := dataSourceRemoteStateGetSchema().Block.InternalValidate(); err != nil {
    15  		t.Fatalf("err: %s", err)
    16  	}
    17  }
    18  
    19  func TestState_basic(t *testing.T) {
    20  	var tests = map[string]struct {
    21  		Config cty.Value
    22  		Want   cty.Value
    23  		Err    bool
    24  	}{
    25  		"basic": {
    26  			cty.ObjectVal(map[string]cty.Value{
    27  				"backend": cty.StringVal("local"),
    28  				"config": cty.ObjectVal(map[string]cty.Value{
    29  					"path": cty.StringVal("./testdata/basic.tfstate"),
    30  				}),
    31  			}),
    32  			cty.ObjectVal(map[string]cty.Value{
    33  				"backend": cty.StringVal("local"),
    34  				"config": cty.ObjectVal(map[string]cty.Value{
    35  					"path": cty.StringVal("./testdata/basic.tfstate"),
    36  				}),
    37  				"outputs": cty.ObjectVal(map[string]cty.Value{
    38  					"foo": cty.StringVal("bar"),
    39  				}),
    40  				"workspace": cty.StringVal(backend.DefaultStateName),
    41  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
    42  			}),
    43  			false,
    44  		},
    45  		"complex outputs": {
    46  			cty.ObjectVal(map[string]cty.Value{
    47  				"backend": cty.StringVal("local"),
    48  				"config": cty.ObjectVal(map[string]cty.Value{
    49  					"path": cty.StringVal("./testdata/complex_outputs.tfstate"),
    50  				}),
    51  			}),
    52  			cty.ObjectVal(map[string]cty.Value{
    53  				"backend": cty.StringVal("local"),
    54  				"config": cty.ObjectVal(map[string]cty.Value{
    55  					"path": cty.StringVal("./testdata/complex_outputs.tfstate"),
    56  				}),
    57  				"outputs": cty.ObjectVal(map[string]cty.Value{
    58  					"computed_map": cty.MapVal(map[string]cty.Value{
    59  						"key1": cty.StringVal("value1"),
    60  					}),
    61  					"computed_set": cty.ListVal([]cty.Value{
    62  						cty.StringVal("setval1"),
    63  						cty.StringVal("setval2"),
    64  					}),
    65  					"map": cty.MapVal(map[string]cty.Value{
    66  						"key":  cty.StringVal("test"),
    67  						"test": cty.StringVal("test"),
    68  					}),
    69  					"set": cty.ListVal([]cty.Value{
    70  						cty.StringVal("test1"),
    71  						cty.StringVal("test2"),
    72  					}),
    73  				}),
    74  				"workspace": cty.StringVal(backend.DefaultStateName),
    75  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
    76  			}),
    77  			false,
    78  		},
    79  		"null outputs": {
    80  			cty.ObjectVal(map[string]cty.Value{
    81  				"backend": cty.StringVal("local"),
    82  				"config": cty.ObjectVal(map[string]cty.Value{
    83  					"path": cty.StringVal("./testdata/null_outputs.tfstate"),
    84  				}),
    85  			}),
    86  			cty.ObjectVal(map[string]cty.Value{
    87  				"backend": cty.StringVal("local"),
    88  				"config": cty.ObjectVal(map[string]cty.Value{
    89  					"path": cty.StringVal("./testdata/null_outputs.tfstate"),
    90  				}),
    91  				"outputs": cty.ObjectVal(map[string]cty.Value{
    92  					"map":  cty.NullVal(cty.DynamicPseudoType),
    93  					"list": cty.NullVal(cty.DynamicPseudoType),
    94  				}),
    95  				"workspace": cty.StringVal(backend.DefaultStateName),
    96  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
    97  			}),
    98  			false,
    99  		},
   100  		"defaults": {
   101  			cty.ObjectVal(map[string]cty.Value{
   102  				"backend": cty.StringVal("local"),
   103  				"config": cty.ObjectVal(map[string]cty.Value{
   104  					"path": cty.StringVal("./testdata/empty.tfstate"),
   105  				}),
   106  				"defaults": cty.ObjectVal(map[string]cty.Value{
   107  					"foo": cty.StringVal("bar"),
   108  				}),
   109  			}),
   110  			cty.ObjectVal(map[string]cty.Value{
   111  				"backend": cty.StringVal("local"),
   112  				"config": cty.ObjectVal(map[string]cty.Value{
   113  					"path": cty.StringVal("./testdata/empty.tfstate"),
   114  				}),
   115  				"defaults": cty.ObjectVal(map[string]cty.Value{
   116  					"foo": cty.StringVal("bar"),
   117  				}),
   118  				"outputs": cty.ObjectVal(map[string]cty.Value{
   119  					"foo": cty.StringVal("bar"),
   120  				}),
   121  				"workspace": cty.StringVal(backend.DefaultStateName),
   122  			}),
   123  			false,
   124  		},
   125  		"future version": {
   126  			cty.ObjectVal(map[string]cty.Value{
   127  				"backend": cty.StringVal("local"),
   128  				"config": cty.ObjectVal(map[string]cty.Value{
   129  					"path": cty.StringVal("./testdata/future.tfstate"),
   130  				}),
   131  			}),
   132  			cty.ObjectVal(map[string]cty.Value{
   133  				"backend": cty.StringVal("local"),
   134  				"config": cty.ObjectVal(map[string]cty.Value{
   135  					"path": cty.StringVal("./testdata/future.tfstate"),
   136  				}),
   137  				"outputs": cty.ObjectVal(map[string]cty.Value{
   138  					"foo": cty.StringVal("bar"),
   139  				}),
   140  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
   141  				"workspace": cty.StringVal(backend.DefaultStateName),
   142  			}),
   143  			false,
   144  		},
   145  		"missing": {
   146  			cty.ObjectVal(map[string]cty.Value{
   147  				"backend": cty.StringVal("local"),
   148  				"config": cty.ObjectVal(map[string]cty.Value{
   149  					"path": cty.StringVal("./testdata/missing.tfstate"), // intentionally not present on disk
   150  				}),
   151  			}),
   152  			cty.ObjectVal(map[string]cty.Value{
   153  				"backend": cty.StringVal("local"),
   154  				"config": cty.ObjectVal(map[string]cty.Value{
   155  					"path": cty.StringVal("./testdata/missing.tfstate"),
   156  				}),
   157  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
   158  				"outputs":   cty.EmptyObjectVal,
   159  				"workspace": cty.StringVal(backend.DefaultStateName),
   160  			}),
   161  			true,
   162  		},
   163  		"wrong type for config": {
   164  			cty.ObjectVal(map[string]cty.Value{
   165  				"backend": cty.StringVal("local"),
   166  				"config":  cty.StringVal("nope"),
   167  			}),
   168  			cty.NilVal,
   169  			true,
   170  		},
   171  		"wrong type for config with unknown backend": {
   172  			cty.ObjectVal(map[string]cty.Value{
   173  				"backend": cty.UnknownVal(cty.String),
   174  				"config":  cty.StringVal("nope"),
   175  			}),
   176  			cty.NilVal,
   177  			true,
   178  		},
   179  		"wrong type for config with unknown config": {
   180  			cty.ObjectVal(map[string]cty.Value{
   181  				"backend": cty.StringVal("local"),
   182  				"config":  cty.UnknownVal(cty.String),
   183  			}),
   184  			cty.NilVal,
   185  			true,
   186  		},
   187  		"wrong type for defaults": {
   188  			cty.ObjectVal(map[string]cty.Value{
   189  				"backend": cty.StringVal("local"),
   190  				"config": cty.ObjectVal(map[string]cty.Value{
   191  					"path": cty.StringVal("./testdata/basic.tfstate"),
   192  				}),
   193  				"defaults": cty.StringVal("nope"),
   194  			}),
   195  			cty.NilVal,
   196  			true,
   197  		},
   198  		"config as map": {
   199  			cty.ObjectVal(map[string]cty.Value{
   200  				"backend": cty.StringVal("local"),
   201  				"config": cty.MapVal(map[string]cty.Value{
   202  					"path": cty.StringVal("./testdata/empty.tfstate"),
   203  				}),
   204  			}),
   205  			cty.ObjectVal(map[string]cty.Value{
   206  				"backend": cty.StringVal("local"),
   207  				"config": cty.MapVal(map[string]cty.Value{
   208  					"path": cty.StringVal("./testdata/empty.tfstate"),
   209  				}),
   210  				"defaults":  cty.NullVal(cty.DynamicPseudoType),
   211  				"outputs":   cty.EmptyObjectVal,
   212  				"workspace": cty.StringVal(backend.DefaultStateName),
   213  			}),
   214  			false,
   215  		},
   216  		"defaults as map": {
   217  			cty.ObjectVal(map[string]cty.Value{
   218  				"backend": cty.StringVal("local"),
   219  				"config": cty.ObjectVal(map[string]cty.Value{
   220  					"path": cty.StringVal("./testdata/basic.tfstate"),
   221  				}),
   222  				"defaults": cty.MapValEmpty(cty.String),
   223  			}),
   224  			cty.ObjectVal(map[string]cty.Value{
   225  				"backend": cty.StringVal("local"),
   226  				"config": cty.ObjectVal(map[string]cty.Value{
   227  					"path": cty.StringVal("./testdata/basic.tfstate"),
   228  				}),
   229  				"defaults": cty.MapValEmpty(cty.String),
   230  				"outputs": cty.ObjectVal(map[string]cty.Value{
   231  					"foo": cty.StringVal("bar"),
   232  				}),
   233  				"workspace": cty.StringVal(backend.DefaultStateName),
   234  			}),
   235  			false,
   236  		},
   237  	}
   238  	for name, test := range tests {
   239  		t.Run(name, func(t *testing.T) {
   240  			schema := dataSourceRemoteStateGetSchema().Block
   241  			config, err := schema.CoerceValue(test.Config)
   242  			if err != nil {
   243  				t.Fatalf("unexpected error: %s", err)
   244  			}
   245  
   246  			diags := dataSourceRemoteStateValidate(config)
   247  
   248  			var got cty.Value
   249  			if !diags.HasErrors() && config.IsWhollyKnown() {
   250  				var moreDiags tfdiags.Diagnostics
   251  				got, moreDiags = dataSourceRemoteStateRead(config)
   252  				diags = diags.Append(moreDiags)
   253  			}
   254  
   255  			if test.Err {
   256  				if !diags.HasErrors() {
   257  					t.Fatal("succeeded; want error")
   258  				}
   259  			} else if diags.HasErrors() {
   260  				t.Fatalf("unexpected errors: %s", diags.Err())
   261  			}
   262  
   263  			if test.Want != cty.NilVal && !test.Want.RawEquals(got) {
   264  				t.Errorf("wrong result\nconfig: %sgot:    %swant:   %s", dump.Value(config), dump.Value(got), dump.Value(test.Want))
   265  			}
   266  		})
   267  	}
   268  }