github.com/bpineau/terraform@v0.8.0-rc1.0.20161126184705-a8886012d185/helper/schema/field_reader_config_test.go (about)

     1  package schema
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/hashicorp/hil/ast"
    10  	"github.com/hashicorp/terraform/config"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  func TestConfigFieldReader_impl(t *testing.T) {
    16  	var _ FieldReader = new(ConfigFieldReader)
    17  }
    18  
    19  func TestConfigFieldReader(t *testing.T) {
    20  	testFieldReader(t, func(s map[string]*Schema) FieldReader {
    21  		return &ConfigFieldReader{
    22  			Schema: s,
    23  
    24  			Config: testConfig(t, map[string]interface{}{
    25  				"bool":   true,
    26  				"float":  3.1415,
    27  				"int":    42,
    28  				"string": "string",
    29  
    30  				"list": []interface{}{"foo", "bar"},
    31  
    32  				"listInt": []interface{}{21, 42},
    33  
    34  				"map": map[string]interface{}{
    35  					"foo": "bar",
    36  					"bar": "baz",
    37  				},
    38  				"mapInt": map[string]interface{}{
    39  					"one": "1",
    40  					"two": "2",
    41  				},
    42  				"mapFloat": map[string]interface{}{
    43  					"oneDotTwo": "1.2",
    44  				},
    45  				"mapBool": map[string]interface{}{
    46  					"True":  "true",
    47  					"False": "false",
    48  				},
    49  
    50  				"set": []interface{}{10, 50},
    51  				"setDeep": []interface{}{
    52  					map[string]interface{}{
    53  						"index": 10,
    54  						"value": "foo",
    55  					},
    56  					map[string]interface{}{
    57  						"index": 50,
    58  						"value": "bar",
    59  					},
    60  				},
    61  			}),
    62  		}
    63  	})
    64  }
    65  
    66  // This contains custom table tests for our ConfigFieldReader
    67  func TestConfigFieldReader_custom(t *testing.T) {
    68  	schema := map[string]*Schema{
    69  		"bool": &Schema{
    70  			Type: TypeBool,
    71  		},
    72  	}
    73  
    74  	cases := map[string]struct {
    75  		Addr   []string
    76  		Result FieldReadResult
    77  		Config *terraform.ResourceConfig
    78  		Err    bool
    79  	}{
    80  		"basic": {
    81  			[]string{"bool"},
    82  			FieldReadResult{
    83  				Value:  true,
    84  				Exists: true,
    85  			},
    86  			testConfig(t, map[string]interface{}{
    87  				"bool": true,
    88  			}),
    89  			false,
    90  		},
    91  
    92  		"computed": {
    93  			[]string{"bool"},
    94  			FieldReadResult{
    95  				Exists:   true,
    96  				Computed: true,
    97  			},
    98  			testConfigInterpolate(t, map[string]interface{}{
    99  				"bool": "${var.foo}",
   100  			}, map[string]ast.Variable{
   101  				"var.foo": ast.Variable{
   102  					Value: config.UnknownVariableValue,
   103  					Type:  ast.TypeString,
   104  				},
   105  			}),
   106  			false,
   107  		},
   108  	}
   109  
   110  	for name, tc := range cases {
   111  		t.Run(name, func(t *testing.T) {
   112  			r := &ConfigFieldReader{
   113  				Schema: schema,
   114  				Config: tc.Config,
   115  			}
   116  			out, err := r.ReadField(tc.Addr)
   117  			if err != nil != tc.Err {
   118  				t.Fatalf("%s: err: %s", name, err)
   119  			}
   120  			if s, ok := out.Value.(*Set); ok {
   121  				// If it is a set, convert to a list so its more easily checked.
   122  				out.Value = s.List()
   123  			}
   124  			if !reflect.DeepEqual(tc.Result, out) {
   125  				t.Fatalf("%s: bad: %#v", name, out)
   126  			}
   127  		})
   128  	}
   129  }
   130  
   131  func TestConfigFieldReader_DefaultHandling(t *testing.T) {
   132  	schema := map[string]*Schema{
   133  		"strWithDefault": &Schema{
   134  			Type:    TypeString,
   135  			Default: "ImADefault",
   136  		},
   137  		"strWithDefaultFunc": &Schema{
   138  			Type: TypeString,
   139  			DefaultFunc: func() (interface{}, error) {
   140  				return "FuncDefault", nil
   141  			},
   142  		},
   143  	}
   144  
   145  	cases := map[string]struct {
   146  		Addr   []string
   147  		Result FieldReadResult
   148  		Config *terraform.ResourceConfig
   149  		Err    bool
   150  	}{
   151  		"gets default value when no config set": {
   152  			[]string{"strWithDefault"},
   153  			FieldReadResult{
   154  				Value:    "ImADefault",
   155  				Exists:   true,
   156  				Computed: false,
   157  			},
   158  			testConfig(t, map[string]interface{}{}),
   159  			false,
   160  		},
   161  		"config overrides default value": {
   162  			[]string{"strWithDefault"},
   163  			FieldReadResult{
   164  				Value:    "fromConfig",
   165  				Exists:   true,
   166  				Computed: false,
   167  			},
   168  			testConfig(t, map[string]interface{}{
   169  				"strWithDefault": "fromConfig",
   170  			}),
   171  			false,
   172  		},
   173  		"gets default from function when no config set": {
   174  			[]string{"strWithDefaultFunc"},
   175  			FieldReadResult{
   176  				Value:    "FuncDefault",
   177  				Exists:   true,
   178  				Computed: false,
   179  			},
   180  			testConfig(t, map[string]interface{}{}),
   181  			false,
   182  		},
   183  		"config overrides default function": {
   184  			[]string{"strWithDefaultFunc"},
   185  			FieldReadResult{
   186  				Value:    "fromConfig",
   187  				Exists:   true,
   188  				Computed: false,
   189  			},
   190  			testConfig(t, map[string]interface{}{
   191  				"strWithDefaultFunc": "fromConfig",
   192  			}),
   193  			false,
   194  		},
   195  	}
   196  
   197  	for name, tc := range cases {
   198  		r := &ConfigFieldReader{
   199  			Schema: schema,
   200  			Config: tc.Config,
   201  		}
   202  		out, err := r.ReadField(tc.Addr)
   203  		if err != nil != tc.Err {
   204  			t.Fatalf("%s: err: %s", name, err)
   205  		}
   206  		if s, ok := out.Value.(*Set); ok {
   207  			// If it is a set, convert to a list so its more easily checked.
   208  			out.Value = s.List()
   209  		}
   210  		if !reflect.DeepEqual(tc.Result, out) {
   211  			t.Fatalf("%s: bad: %#v", name, out)
   212  		}
   213  	}
   214  }
   215  
   216  func TestConfigFieldReader_ComputedMap(t *testing.T) {
   217  	schema := map[string]*Schema{
   218  		"map": &Schema{
   219  			Type:     TypeMap,
   220  			Computed: true,
   221  		},
   222  	}
   223  
   224  	cases := map[string]struct {
   225  		Addr   []string
   226  		Result FieldReadResult
   227  		Config *terraform.ResourceConfig
   228  		Err    bool
   229  	}{
   230  		"set, normal": {
   231  			[]string{"map"},
   232  			FieldReadResult{
   233  				Value: map[string]interface{}{
   234  					"foo": "bar",
   235  				},
   236  				Exists:   true,
   237  				Computed: false,
   238  			},
   239  			testConfig(t, map[string]interface{}{
   240  				"map": map[string]interface{}{
   241  					"foo": "bar",
   242  				},
   243  			}),
   244  			false,
   245  		},
   246  
   247  		"computed element": {
   248  			[]string{"map"},
   249  			FieldReadResult{
   250  				Exists:   true,
   251  				Computed: true,
   252  			},
   253  			testConfigInterpolate(t, map[string]interface{}{
   254  				"map": map[string]interface{}{
   255  					"foo": "${var.foo}",
   256  				},
   257  			}, map[string]ast.Variable{
   258  				"var.foo": ast.Variable{
   259  					Value: config.UnknownVariableValue,
   260  					Type:  ast.TypeString,
   261  				},
   262  			}),
   263  			false,
   264  		},
   265  
   266  		"native map": {
   267  			[]string{"map"},
   268  			FieldReadResult{
   269  				Value: map[string]interface{}{
   270  					"bar": "baz",
   271  					"baz": "bar",
   272  				},
   273  				Exists:   true,
   274  				Computed: false,
   275  			},
   276  			testConfigInterpolate(t, map[string]interface{}{
   277  				"map": "${var.foo}",
   278  			}, map[string]ast.Variable{
   279  				"var.foo": ast.Variable{
   280  					Type: ast.TypeMap,
   281  					Value: map[string]ast.Variable{
   282  						"bar": ast.Variable{
   283  							Type:  ast.TypeString,
   284  							Value: "baz",
   285  						},
   286  						"baz": ast.Variable{
   287  							Type:  ast.TypeString,
   288  							Value: "bar",
   289  						},
   290  					},
   291  				},
   292  			}),
   293  			false,
   294  		},
   295  	}
   296  
   297  	for name, tc := range cases {
   298  		r := &ConfigFieldReader{
   299  			Schema: schema,
   300  			Config: tc.Config,
   301  		}
   302  		out, err := r.ReadField(tc.Addr)
   303  		if err != nil != tc.Err {
   304  			t.Fatalf("%s: err: %s", name, err)
   305  		}
   306  		if s, ok := out.Value.(*Set); ok {
   307  			// If it is a set, convert to the raw map
   308  			out.Value = s.m
   309  			if len(s.m) == 0 {
   310  				out.Value = nil
   311  			}
   312  		}
   313  		if !reflect.DeepEqual(tc.Result, out) {
   314  			t.Fatalf("%s: bad: %#v", name, out)
   315  		}
   316  	}
   317  }
   318  
   319  func TestConfigFieldReader_ComputedSet(t *testing.T) {
   320  	schema := map[string]*Schema{
   321  		"strSet": &Schema{
   322  			Type: TypeSet,
   323  			Elem: &Schema{Type: TypeString},
   324  			Set:  HashString,
   325  		},
   326  	}
   327  
   328  	cases := map[string]struct {
   329  		Addr   []string
   330  		Result FieldReadResult
   331  		Config *terraform.ResourceConfig
   332  		Err    bool
   333  	}{
   334  		"set, normal": {
   335  			[]string{"strSet"},
   336  			FieldReadResult{
   337  				Value: map[string]interface{}{
   338  					"2356372769": "foo",
   339  				},
   340  				Exists:   true,
   341  				Computed: false,
   342  			},
   343  			testConfig(t, map[string]interface{}{
   344  				"strSet": []interface{}{"foo"},
   345  			}),
   346  			false,
   347  		},
   348  
   349  		"set, computed element": {
   350  			[]string{"strSet"},
   351  			FieldReadResult{
   352  				Value:    nil,
   353  				Exists:   true,
   354  				Computed: true,
   355  			},
   356  			testConfigInterpolate(t, map[string]interface{}{
   357  				"strSet": []interface{}{"${var.foo}"},
   358  			}, map[string]ast.Variable{
   359  				"var.foo": ast.Variable{
   360  					Value: config.UnknownVariableValue,
   361  					Type:  ast.TypeUnknown,
   362  				},
   363  			}),
   364  			false,
   365  		},
   366  
   367  		"set, computed element substring": {
   368  			[]string{"strSet"},
   369  			FieldReadResult{
   370  				Value:    nil,
   371  				Exists:   true,
   372  				Computed: true,
   373  			},
   374  			testConfigInterpolate(t, map[string]interface{}{
   375  				"strSet": []interface{}{"${var.foo}/32"},
   376  			}, map[string]ast.Variable{
   377  				"var.foo": ast.Variable{
   378  					Value: config.UnknownVariableValue,
   379  					Type:  ast.TypeUnknown,
   380  				},
   381  			}),
   382  			false,
   383  		},
   384  	}
   385  
   386  	for name, tc := range cases {
   387  		r := &ConfigFieldReader{
   388  			Schema: schema,
   389  			Config: tc.Config,
   390  		}
   391  		out, err := r.ReadField(tc.Addr)
   392  		if err != nil != tc.Err {
   393  			t.Fatalf("%s: err: %s", name, err)
   394  		}
   395  		if s, ok := out.Value.(*Set); ok {
   396  			// If it is a set, convert to the raw map
   397  			out.Value = s.m
   398  			if len(s.m) == 0 {
   399  				out.Value = nil
   400  			}
   401  		}
   402  		if !reflect.DeepEqual(tc.Result, out) {
   403  			t.Fatalf("%s: bad: %#v", name, out)
   404  		}
   405  	}
   406  }
   407  
   408  func TestConfigFieldReader_computedComplexSet(t *testing.T) {
   409  	hashfunc := func(v interface{}) int {
   410  		var buf bytes.Buffer
   411  		m := v.(map[string]interface{})
   412  		buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
   413  		buf.WriteString(fmt.Sprintf("%s-", m["vhd_uri"].(string)))
   414  		return hashcode.String(buf.String())
   415  	}
   416  
   417  	schema := map[string]*Schema{
   418  		"set": &Schema{
   419  			Type: TypeSet,
   420  			Elem: &Resource{
   421  				Schema: map[string]*Schema{
   422  					"name": {
   423  						Type:     TypeString,
   424  						Required: true,
   425  					},
   426  
   427  					"vhd_uri": {
   428  						Type:     TypeString,
   429  						Required: true,
   430  					},
   431  				},
   432  			},
   433  			Set: hashfunc,
   434  		},
   435  	}
   436  
   437  	cases := map[string]struct {
   438  		Addr   []string
   439  		Result FieldReadResult
   440  		Config *terraform.ResourceConfig
   441  		Err    bool
   442  	}{
   443  		"set, normal": {
   444  			[]string{"set"},
   445  			FieldReadResult{
   446  				Value: map[string]interface{}{
   447  					"532860136": map[string]interface{}{
   448  						"name":    "myosdisk1",
   449  						"vhd_uri": "bar",
   450  					},
   451  				},
   452  				Exists:   true,
   453  				Computed: false,
   454  			},
   455  			testConfig(t, map[string]interface{}{
   456  				"set": []interface{}{
   457  					map[string]interface{}{
   458  						"name":    "myosdisk1",
   459  						"vhd_uri": "bar",
   460  					},
   461  				},
   462  			}),
   463  			false,
   464  		},
   465  
   466  		"set, computed element": {
   467  			[]string{"set"},
   468  			FieldReadResult{
   469  				Value: map[string]interface{}{
   470  					"~3596295623": map[string]interface{}{
   471  						"name":    "myosdisk1",
   472  						"vhd_uri": "${var.foo}/bar",
   473  					},
   474  				},
   475  				Exists:   true,
   476  				Computed: false,
   477  			},
   478  			testConfigInterpolate(t, map[string]interface{}{
   479  				"set": []interface{}{
   480  					map[string]interface{}{
   481  						"name":    "myosdisk1",
   482  						"vhd_uri": "${var.foo}/bar",
   483  					},
   484  				},
   485  			}, map[string]ast.Variable{
   486  				"var.foo": ast.Variable{
   487  					Value: config.UnknownVariableValue,
   488  					Type:  ast.TypeUnknown,
   489  				},
   490  			}),
   491  			false,
   492  		},
   493  
   494  		"set, computed element single": {
   495  			[]string{"set", "~3596295623", "vhd_uri"},
   496  			FieldReadResult{
   497  				Value:    "${var.foo}/bar",
   498  				Exists:   true,
   499  				Computed: true,
   500  			},
   501  			testConfigInterpolate(t, map[string]interface{}{
   502  				"set": []interface{}{
   503  					map[string]interface{}{
   504  						"name":    "myosdisk1",
   505  						"vhd_uri": "${var.foo}/bar",
   506  					},
   507  				},
   508  			}, map[string]ast.Variable{
   509  				"var.foo": ast.Variable{
   510  					Value: config.UnknownVariableValue,
   511  					Type:  ast.TypeUnknown,
   512  				},
   513  			}),
   514  			false,
   515  		},
   516  	}
   517  
   518  	for name, tc := range cases {
   519  		r := &ConfigFieldReader{
   520  			Schema: schema,
   521  			Config: tc.Config,
   522  		}
   523  		out, err := r.ReadField(tc.Addr)
   524  		if err != nil != tc.Err {
   525  			t.Fatalf("%s: err: %s", name, err)
   526  		}
   527  		if s, ok := out.Value.(*Set); ok {
   528  			// If it is a set, convert to the raw map
   529  			out.Value = s.m
   530  			if len(s.m) == 0 {
   531  				out.Value = nil
   532  			}
   533  		}
   534  		if !reflect.DeepEqual(tc.Result, out) {
   535  			t.Fatalf("%s: bad: %#v", name, out)
   536  		}
   537  	}
   538  }
   539  
   540  func testConfig(
   541  	t *testing.T, raw map[string]interface{}) *terraform.ResourceConfig {
   542  	return testConfigInterpolate(t, raw, nil)
   543  }
   544  
   545  func testConfigInterpolate(
   546  	t *testing.T,
   547  	raw map[string]interface{},
   548  	vs map[string]ast.Variable) *terraform.ResourceConfig {
   549  
   550  	rc, err := config.NewRawConfig(raw)
   551  	if err != nil {
   552  		t.Fatalf("err: %s", err)
   553  	}
   554  	if len(vs) > 0 {
   555  		if err := rc.Interpolate(vs); err != nil {
   556  			t.Fatalf("err: %s", err)
   557  		}
   558  	}
   559  
   560  	return terraform.NewResourceConfig(rc)
   561  }