github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/interpolate_test.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "os" 6 "reflect" 7 "sync" 8 "testing" 9 10 "github.com/hashicorp/terraform/config" 11 "github.com/hashicorp/terraform/config/lang/ast" 12 ) 13 14 func TestInterpolater_countIndex(t *testing.T) { 15 i := &Interpolater{} 16 17 scope := &InterpolationScope{ 18 Path: rootModulePath, 19 Resource: &Resource{CountIndex: 42}, 20 } 21 22 testInterpolate(t, i, scope, "count.index", ast.Variable{ 23 Value: 42, 24 Type: ast.TypeInt, 25 }) 26 } 27 28 func TestInterpolater_countIndexInWrongContext(t *testing.T) { 29 i := &Interpolater{} 30 31 scope := &InterpolationScope{ 32 Path: rootModulePath, 33 } 34 35 n := "count.index" 36 37 v, err := config.NewInterpolatedVariable(n) 38 if err != nil { 39 t.Fatalf("err: %s", err) 40 } 41 42 expectedErr := fmt.Errorf("foo: count.index is only valid within resources") 43 44 _, err = i.Values(scope, map[string]config.InterpolatedVariable{ 45 "foo": v, 46 }) 47 48 if !reflect.DeepEqual(expectedErr, err) { 49 t.Fatalf("expected: %#v, got %#v", expectedErr, err) 50 } 51 } 52 53 func TestInterpolater_moduleVariable(t *testing.T) { 54 lock := new(sync.RWMutex) 55 state := &State{ 56 Modules: []*ModuleState{ 57 &ModuleState{ 58 Path: rootModulePath, 59 Resources: map[string]*ResourceState{ 60 "aws_instance.web": &ResourceState{ 61 Type: "aws_instance", 62 Primary: &InstanceState{ 63 ID: "bar", 64 }, 65 }, 66 }, 67 }, 68 &ModuleState{ 69 Path: []string{RootModuleName, "child"}, 70 Outputs: map[string]string{ 71 "foo": "bar", 72 }, 73 }, 74 }, 75 } 76 77 i := &Interpolater{ 78 State: state, 79 StateLock: lock, 80 } 81 82 scope := &InterpolationScope{ 83 Path: rootModulePath, 84 } 85 86 testInterpolate(t, i, scope, "module.child.foo", ast.Variable{ 87 Value: "bar", 88 Type: ast.TypeString, 89 }) 90 } 91 92 func TestInterpolater_pathCwd(t *testing.T) { 93 i := &Interpolater{} 94 scope := &InterpolationScope{} 95 96 expected, err := os.Getwd() 97 if err != nil { 98 t.Fatalf("err: %s", err) 99 } 100 101 testInterpolate(t, i, scope, "path.cwd", ast.Variable{ 102 Value: expected, 103 Type: ast.TypeString, 104 }) 105 } 106 107 func TestInterpolater_pathModule(t *testing.T) { 108 mod := testModule(t, "interpolate-path-module") 109 i := &Interpolater{ 110 Module: mod, 111 } 112 scope := &InterpolationScope{ 113 Path: []string{RootModuleName, "child"}, 114 } 115 116 path := mod.Child([]string{"child"}).Config().Dir 117 testInterpolate(t, i, scope, "path.module", ast.Variable{ 118 Value: path, 119 Type: ast.TypeString, 120 }) 121 } 122 123 func TestInterpolater_pathRoot(t *testing.T) { 124 mod := testModule(t, "interpolate-path-module") 125 i := &Interpolater{ 126 Module: mod, 127 } 128 scope := &InterpolationScope{ 129 Path: []string{RootModuleName, "child"}, 130 } 131 132 path := mod.Config().Dir 133 testInterpolate(t, i, scope, "path.root", ast.Variable{ 134 Value: path, 135 Type: ast.TypeString, 136 }) 137 } 138 139 func TestInterpolater_resourceVariable(t *testing.T) { 140 lock := new(sync.RWMutex) 141 state := &State{ 142 Modules: []*ModuleState{ 143 &ModuleState{ 144 Path: rootModulePath, 145 Resources: map[string]*ResourceState{ 146 "aws_instance.web": &ResourceState{ 147 Type: "aws_instance", 148 Primary: &InstanceState{ 149 ID: "bar", 150 Attributes: map[string]string{ 151 "foo": "bar", 152 }, 153 }, 154 }, 155 }, 156 }, 157 }, 158 } 159 160 i := &Interpolater{ 161 Module: testModule(t, "interpolate-resource-variable"), 162 State: state, 163 StateLock: lock, 164 } 165 166 scope := &InterpolationScope{ 167 Path: rootModulePath, 168 } 169 170 testInterpolate(t, i, scope, "aws_instance.web.foo", ast.Variable{ 171 Value: "bar", 172 Type: ast.TypeString, 173 }) 174 } 175 176 func TestInterpolater_resourceVariableMulti(t *testing.T) { 177 lock := new(sync.RWMutex) 178 state := &State{ 179 Modules: []*ModuleState{ 180 &ModuleState{ 181 Path: rootModulePath, 182 Resources: map[string]*ResourceState{ 183 "aws_instance.web": &ResourceState{ 184 Type: "aws_instance", 185 Primary: &InstanceState{ 186 ID: "bar", 187 Attributes: map[string]string{ 188 "foo": config.UnknownVariableValue, 189 }, 190 }, 191 }, 192 }, 193 }, 194 }, 195 } 196 197 i := &Interpolater{ 198 Module: testModule(t, "interpolate-resource-variable"), 199 State: state, 200 StateLock: lock, 201 } 202 203 scope := &InterpolationScope{ 204 Path: rootModulePath, 205 } 206 207 testInterpolate(t, i, scope, "aws_instance.web.*.foo", ast.Variable{ 208 Value: config.UnknownVariableValue, 209 Type: ast.TypeString, 210 }) 211 } 212 213 func TestInterpolator_resourceMultiAttributes(t *testing.T) { 214 lock := new(sync.RWMutex) 215 state := &State{ 216 Modules: []*ModuleState{ 217 &ModuleState{ 218 Path: rootModulePath, 219 Resources: map[string]*ResourceState{ 220 "aws_route53_zone.yada": &ResourceState{ 221 Type: "aws_route53_zone", 222 Dependencies: []string{}, 223 Primary: &InstanceState{ 224 ID: "AAABBBCCCDDDEEE", 225 Attributes: map[string]string{ 226 "name_servers.#": "4", 227 "name_servers.0": "ns-1334.awsdns-38.org", 228 "name_servers.1": "ns-1680.awsdns-18.co.uk", 229 "name_servers.2": "ns-498.awsdns-62.com", 230 "name_servers.3": "ns-601.awsdns-11.net", 231 "listeners.#": "1", 232 "listeners.0": "red", 233 "tags.#": "1", 234 "tags.Name": "reindeer", 235 "nothing.#": "0", 236 }, 237 }, 238 }, 239 }, 240 }, 241 }, 242 } 243 244 i := &Interpolater{ 245 Module: testModule(t, "interpolate-multi-vars"), 246 StateLock: lock, 247 State: state, 248 } 249 250 scope := &InterpolationScope{ 251 Path: rootModulePath, 252 } 253 254 name_servers := []string{ 255 "ns-1334.awsdns-38.org", 256 "ns-1680.awsdns-18.co.uk", 257 "ns-498.awsdns-62.com", 258 "ns-601.awsdns-11.net", 259 } 260 expectedNameServers := config.NewStringList(name_servers).String() 261 262 // More than 1 element 263 testInterpolate(t, i, scope, "aws_route53_zone.yada.name_servers", ast.Variable{ 264 Value: expectedNameServers, 265 Type: ast.TypeString, 266 }) 267 268 // Exactly 1 element 269 testInterpolate(t, i, scope, "aws_route53_zone.yada.listeners", ast.Variable{ 270 Value: config.NewStringList([]string{"red"}).String(), 271 Type: ast.TypeString, 272 }) 273 274 // Zero elements 275 testInterpolate(t, i, scope, "aws_route53_zone.yada.nothing", ast.Variable{ 276 Value: config.NewStringList([]string{}).String(), 277 Type: ast.TypeString, 278 }) 279 280 // Maps still need to work 281 testInterpolate(t, i, scope, "aws_route53_zone.yada.tags.Name", ast.Variable{ 282 Value: "reindeer", 283 Type: ast.TypeString, 284 }) 285 } 286 287 func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { 288 i := getInterpolaterFixture(t) 289 scope := &InterpolationScope{ 290 Path: rootModulePath, 291 } 292 293 name_servers := []string{ 294 "ns-1334.awsdns-38.org", 295 "ns-1680.awsdns-18.co.uk", 296 "ns-498.awsdns-62.com", 297 "ns-601.awsdns-11.net", 298 "ns-000.awsdns-38.org", 299 "ns-444.awsdns-18.co.uk", 300 "ns-666.awsdns-11.net", 301 "ns-999.awsdns-62.com", 302 } 303 304 // More than 1 element 305 expectedNameServers := config.NewStringList(name_servers[0:4]).String() 306 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.name_servers", ast.Variable{ 307 Value: expectedNameServers, 308 Type: ast.TypeString, 309 }) 310 // More than 1 element in both 311 expectedNameServers = config.NewStringList(name_servers).String() 312 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.name_servers", ast.Variable{ 313 Value: expectedNameServers, 314 Type: ast.TypeString, 315 }) 316 317 // Exactly 1 element 318 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.listeners", ast.Variable{ 319 Value: config.NewStringList([]string{"red"}).String(), 320 Type: ast.TypeString, 321 }) 322 // Exactly 1 element in both 323 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.listeners", ast.Variable{ 324 Value: config.NewStringList([]string{"red", "blue"}).String(), 325 Type: ast.TypeString, 326 }) 327 328 // Zero elements 329 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.nothing", ast.Variable{ 330 Value: config.NewStringList([]string{}).String(), 331 Type: ast.TypeString, 332 }) 333 // Zero + 1 element 334 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.special", ast.Variable{ 335 Value: config.NewStringList([]string{"extra"}).String(), 336 Type: ast.TypeString, 337 }) 338 339 // Maps still need to work 340 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.tags.Name", ast.Variable{ 341 Value: "reindeer", 342 Type: ast.TypeString, 343 }) 344 // Maps still need to work in both 345 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.tags.Name", ast.Variable{ 346 Value: config.NewStringList([]string{"reindeer", "white-hart"}).String(), 347 Type: ast.TypeString, 348 }) 349 } 350 351 func getInterpolaterFixture(t *testing.T) *Interpolater { 352 lock := new(sync.RWMutex) 353 state := &State{ 354 Modules: []*ModuleState{ 355 &ModuleState{ 356 Path: rootModulePath, 357 Resources: map[string]*ResourceState{ 358 "aws_route53_zone.terra.0": &ResourceState{ 359 Type: "aws_route53_zone", 360 Dependencies: []string{}, 361 Primary: &InstanceState{ 362 ID: "AAABBBCCCDDDEEE", 363 Attributes: map[string]string{ 364 "name_servers.#": "4", 365 "name_servers.0": "ns-1334.awsdns-38.org", 366 "name_servers.1": "ns-1680.awsdns-18.co.uk", 367 "name_servers.2": "ns-498.awsdns-62.com", 368 "name_servers.3": "ns-601.awsdns-11.net", 369 "listeners.#": "1", 370 "listeners.0": "red", 371 "tags.#": "1", 372 "tags.Name": "reindeer", 373 "nothing.#": "0", 374 }, 375 }, 376 }, 377 "aws_route53_zone.terra.1": &ResourceState{ 378 Type: "aws_route53_zone", 379 Dependencies: []string{}, 380 Primary: &InstanceState{ 381 ID: "EEEFFFGGGHHHIII", 382 Attributes: map[string]string{ 383 "name_servers.#": "4", 384 "name_servers.0": "ns-000.awsdns-38.org", 385 "name_servers.1": "ns-444.awsdns-18.co.uk", 386 "name_servers.2": "ns-999.awsdns-62.com", 387 "name_servers.3": "ns-666.awsdns-11.net", 388 "listeners.#": "1", 389 "listeners.0": "blue", 390 "special.#": "1", 391 "special.0": "extra", 392 "tags.#": "1", 393 "tags.Name": "white-hart", 394 "nothing.#": "0", 395 }, 396 }, 397 }, 398 }, 399 }, 400 }, 401 } 402 403 return &Interpolater{ 404 Module: testModule(t, "interpolate-multi-vars"), 405 StateLock: lock, 406 State: state, 407 } 408 } 409 410 func testInterpolate( 411 t *testing.T, i *Interpolater, 412 scope *InterpolationScope, 413 n string, expectedVar ast.Variable) { 414 v, err := config.NewInterpolatedVariable(n) 415 if err != nil { 416 t.Fatalf("err: %s", err) 417 } 418 419 actual, err := i.Values(scope, map[string]config.InterpolatedVariable{ 420 "foo": v, 421 }) 422 if err != nil { 423 t.Fatalf("err: %s", err) 424 } 425 426 expected := map[string]ast.Variable{ 427 "foo": expectedVar, 428 } 429 if !reflect.DeepEqual(actual, expected) { 430 t.Fatalf("%q: actual: %#v\nexpected: %#v", n, actual, expected) 431 } 432 }