github.com/armen/terraform@v0.5.2-0.20150529052519-caa8117a08f1/config/interpolate_funcs_test.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/terraform/config/lang"
    11  	"github.com/hashicorp/terraform/config/lang/ast"
    12  )
    13  
    14  func TestInterpolateFuncConcat(t *testing.T) {
    15  	testFunction(t, testFunctionConfig{
    16  		Cases: []testFunctionCase{
    17  			{
    18  				`${concat("foo", "bar")}`,
    19  				"foobar",
    20  				false,
    21  			},
    22  
    23  			{
    24  				`${concat("foo")}`,
    25  				"foo",
    26  				false,
    27  			},
    28  
    29  			{
    30  				`${concat()}`,
    31  				nil,
    32  				true,
    33  			},
    34  		},
    35  	})
    36  }
    37  
    38  func TestInterpolateFuncFile(t *testing.T) {
    39  	tf, err := ioutil.TempFile("", "tf")
    40  	if err != nil {
    41  		t.Fatalf("err: %s", err)
    42  	}
    43  	path := tf.Name()
    44  	tf.Write([]byte("foo"))
    45  	tf.Close()
    46  	defer os.Remove(path)
    47  
    48  	testFunction(t, testFunctionConfig{
    49  		Cases: []testFunctionCase{
    50  			{
    51  				fmt.Sprintf(`${file("%s")}`, path),
    52  				"foo",
    53  				false,
    54  			},
    55  
    56  			// Invalid path
    57  			{
    58  				`${file("/i/dont/exist")}`,
    59  				nil,
    60  				true,
    61  			},
    62  
    63  			// Too many args
    64  			{
    65  				`${file("foo", "bar")}`,
    66  				nil,
    67  				true,
    68  			},
    69  		},
    70  	})
    71  }
    72  
    73  func TestInterpolateFuncFormat(t *testing.T) {
    74  	testFunction(t, testFunctionConfig{
    75  		Cases: []testFunctionCase{
    76  			{
    77  				`${format("hello")}`,
    78  				"hello",
    79  				false,
    80  			},
    81  
    82  			{
    83  				`${format("hello %s", "world")}`,
    84  				"hello world",
    85  				false,
    86  			},
    87  
    88  			{
    89  				`${format("hello %d", 42)}`,
    90  				"hello 42",
    91  				false,
    92  			},
    93  
    94  			{
    95  				`${format("hello %05d", 42)}`,
    96  				"hello 00042",
    97  				false,
    98  			},
    99  
   100  			{
   101  				`${format("hello %05d", 12345)}`,
   102  				"hello 12345",
   103  				false,
   104  			},
   105  		},
   106  	})
   107  }
   108  
   109  func TestInterpolateFuncFormatList(t *testing.T) {
   110  	testFunction(t, testFunctionConfig{
   111  		Cases: []testFunctionCase{
   112  			// formatlist requires at least one list
   113  			{
   114  				`${formatlist("hello")}`,
   115  				nil,
   116  				true,
   117  			},
   118  			{
   119  				`${formatlist("hello %s", "world")}`,
   120  				nil,
   121  				true,
   122  			},
   123  			// formatlist applies to each list element in turn
   124  			{
   125  				`${formatlist("<%s>", split(",", "A,B"))}`,
   126  				"<A>" + InterpSplitDelim + "<B>",
   127  				false,
   128  			},
   129  			// formatlist repeats scalar elements
   130  			{
   131  				`${join(", ", formatlist("%s=%s", "x", split(",", "A,B,C")))}`,
   132  				"x=A, x=B, x=C",
   133  				false,
   134  			},
   135  			// Multiple lists are walked in parallel
   136  			{
   137  				`${join(", ", formatlist("%s=%s", split(",", "A,B,C"), split(",", "1,2,3")))}`,
   138  				"A=1, B=2, C=3",
   139  				false,
   140  			},
   141  			// formatlist of lists of length zero/one are repeated, just as scalars are
   142  			{
   143  				`${join(", ", formatlist("%s=%s", split(",", ""), split(",", "1,2,3")))}`,
   144  				"=1, =2, =3",
   145  				false,
   146  			},
   147  			{
   148  				`${join(", ", formatlist("%s=%s", split(",", "A"), split(",", "1,2,3")))}`,
   149  				"A=1, A=2, A=3",
   150  				false,
   151  			},
   152  			// Mismatched list lengths generate an error
   153  			{
   154  				`${formatlist("%s=%2s", split(",", "A,B,C,D"), split(",", "1,2,3"))}`,
   155  				nil,
   156  				true,
   157  			},
   158  		},
   159  	})
   160  }
   161  
   162  func TestInterpolateFuncJoin(t *testing.T) {
   163  	testFunction(t, testFunctionConfig{
   164  		Cases: []testFunctionCase{
   165  			{
   166  				`${join(",")}`,
   167  				nil,
   168  				true,
   169  			},
   170  
   171  			{
   172  				`${join(",", "foo")}`,
   173  				"foo",
   174  				false,
   175  			},
   176  
   177  			/*
   178  				TODO
   179  				{
   180  					`${join(",", "foo", "bar")}`,
   181  					"foo,bar",
   182  					false,
   183  				},
   184  			*/
   185  
   186  			{
   187  				fmt.Sprintf(`${join(".", "%s")}`,
   188  					fmt.Sprintf(
   189  						"foo%sbar%sbaz",
   190  						InterpSplitDelim,
   191  						InterpSplitDelim)),
   192  				"foo.bar.baz",
   193  				false,
   194  			},
   195  		},
   196  	})
   197  }
   198  
   199  func TestInterpolateFuncReplace(t *testing.T) {
   200  	testFunction(t, testFunctionConfig{
   201  		Cases: []testFunctionCase{
   202  			// Regular search and replace
   203  			{
   204  				`${replace("hello", "hel", "bel")}`,
   205  				"bello",
   206  				false,
   207  			},
   208  
   209  			// Search string doesn't match
   210  			{
   211  				`${replace("hello", "nope", "bel")}`,
   212  				"hello",
   213  				false,
   214  			},
   215  
   216  			// Regular expression
   217  			{
   218  				`${replace("hello", "/l/", "L")}`,
   219  				"heLLo",
   220  				false,
   221  			},
   222  
   223  			{
   224  				`${replace("helo", "/(l)/", "$1$1")}`,
   225  				"hello",
   226  				false,
   227  			},
   228  
   229  			// Bad regexp
   230  			{
   231  				`${replace("helo", "/(l/", "$1$1")}`,
   232  				nil,
   233  				true,
   234  			},
   235  		},
   236  	})
   237  }
   238  
   239  func TestInterpolateFuncLength(t *testing.T) {
   240  	testFunction(t, testFunctionConfig{
   241  		Cases: []testFunctionCase{
   242  			// Raw strings
   243  			{
   244  				`${length("")}`,
   245  				"0",
   246  				false,
   247  			},
   248  			{
   249  				`${length("a")}`,
   250  				"1",
   251  				false,
   252  			},
   253  			{
   254  				`${length(" ")}`,
   255  				"1",
   256  				false,
   257  			},
   258  			{
   259  				`${length(" a ,")}`,
   260  				"4",
   261  				false,
   262  			},
   263  			{
   264  				`${length("aaa")}`,
   265  				"3",
   266  				false,
   267  			},
   268  
   269  			// Lists
   270  			{
   271  				`${length(split(",", "a"))}`,
   272  				"1",
   273  				false,
   274  			},
   275  			{
   276  				`${length(split(",", "foo,"))}`,
   277  				"2",
   278  				false,
   279  			},
   280  			{
   281  				`${length(split(",", ",foo,"))}`,
   282  				"3",
   283  				false,
   284  			},
   285  			{
   286  				`${length(split(",", "foo,bar"))}`,
   287  				"2",
   288  				false,
   289  			},
   290  			{
   291  				`${length(split(".", "one.two.three.four.five"))}`,
   292  				"5",
   293  				false,
   294  			},
   295  		},
   296  	})
   297  }
   298  
   299  func TestInterpolateFuncSplit(t *testing.T) {
   300  	testFunction(t, testFunctionConfig{
   301  		Cases: []testFunctionCase{
   302  			{
   303  				`${split(",")}`,
   304  				nil,
   305  				true,
   306  			},
   307  
   308  			{
   309  				`${split(",", "foo")}`,
   310  				"foo",
   311  				false,
   312  			},
   313  
   314  			{
   315  				`${split(",", ",,,")}`,
   316  				fmt.Sprintf(
   317  					"%s%s%s",
   318  					InterpSplitDelim,
   319  					InterpSplitDelim,
   320  					InterpSplitDelim),
   321  				false,
   322  			},
   323  
   324  			{
   325  				`${split(",", "foo,")}`,
   326  				fmt.Sprintf(
   327  					"%s%s",
   328  					"foo",
   329  					InterpSplitDelim),
   330  				false,
   331  			},
   332  
   333  			{
   334  				`${split(",", ",foo,")}`,
   335  				fmt.Sprintf(
   336  					"%s%s%s",
   337  					InterpSplitDelim,
   338  					"foo",
   339  					InterpSplitDelim),
   340  				false,
   341  			},
   342  
   343  			{
   344  				`${split(".", "foo.bar.baz")}`,
   345  				fmt.Sprintf(
   346  					"foo%sbar%sbaz",
   347  					InterpSplitDelim,
   348  					InterpSplitDelim),
   349  				false,
   350  			},
   351  		},
   352  	})
   353  }
   354  
   355  func TestInterpolateFuncLookup(t *testing.T) {
   356  	testFunction(t, testFunctionConfig{
   357  		Vars: map[string]ast.Variable{
   358  			"var.foo.bar": ast.Variable{
   359  				Value: "baz",
   360  				Type:  ast.TypeString,
   361  			},
   362  		},
   363  		Cases: []testFunctionCase{
   364  			{
   365  				`${lookup("foo", "bar")}`,
   366  				"baz",
   367  				false,
   368  			},
   369  
   370  			// Invalid key
   371  			{
   372  				`${lookup("foo", "baz")}`,
   373  				nil,
   374  				true,
   375  			},
   376  
   377  			// Too many args
   378  			{
   379  				`${lookup("foo", "bar", "baz")}`,
   380  				nil,
   381  				true,
   382  			},
   383  		},
   384  	})
   385  }
   386  
   387  func TestInterpolateFuncElement(t *testing.T) {
   388  	testFunction(t, testFunctionConfig{
   389  		Cases: []testFunctionCase{
   390  			{
   391  				fmt.Sprintf(`${element("%s", "1")}`,
   392  					"foo"+InterpSplitDelim+"baz"),
   393  				"baz",
   394  				false,
   395  			},
   396  
   397  			{
   398  				`${element("foo", "0")}`,
   399  				"foo",
   400  				false,
   401  			},
   402  
   403  			// Invalid index should wrap vs. out-of-bounds
   404  			{
   405  				fmt.Sprintf(`${element("%s", "2")}`,
   406  					"foo"+InterpSplitDelim+"baz"),
   407  				"foo",
   408  				false,
   409  			},
   410  
   411  			// Too many args
   412  			{
   413  				fmt.Sprintf(`${element("%s", "0", "2")}`,
   414  					"foo"+InterpSplitDelim+"baz"),
   415  				nil,
   416  				true,
   417  			},
   418  		},
   419  	})
   420  }
   421  
   422  type testFunctionConfig struct {
   423  	Cases []testFunctionCase
   424  	Vars  map[string]ast.Variable
   425  }
   426  
   427  type testFunctionCase struct {
   428  	Input  string
   429  	Result interface{}
   430  	Error  bool
   431  }
   432  
   433  func testFunction(t *testing.T, config testFunctionConfig) {
   434  	for i, tc := range config.Cases {
   435  		ast, err := lang.Parse(tc.Input)
   436  		if err != nil {
   437  			t.Fatalf("%d: err: %s", i, err)
   438  		}
   439  
   440  		out, _, err := lang.Eval(ast, langEvalConfig(config.Vars))
   441  		if (err != nil) != tc.Error {
   442  			t.Fatalf("%d: err: %s", i, err)
   443  		}
   444  
   445  		if !reflect.DeepEqual(out, tc.Result) {
   446  			t.Fatalf(
   447  				"%d: bad output for input: %s\n\nOutput: %#v\nExpected: %#v",
   448  				i, tc.Input, out, tc.Result)
   449  		}
   450  	}
   451  }