github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/test/resource_test.go (about) 1 package test 2 3 import ( 4 "reflect" 5 "regexp" 6 "strings" 7 "testing" 8 9 "github.com/hashicorp/terraform/helper/resource" 10 "github.com/hashicorp/terraform/terraform" 11 ) 12 13 func TestResource_basic(t *testing.T) { 14 resource.UnitTest(t, resource.TestCase{ 15 Providers: testAccProviders, 16 CheckDestroy: testAccCheckResourceDestroy, 17 Steps: []resource.TestStep{ 18 resource.TestStep{ 19 Config: strings.TrimSpace(` 20 resource "test_resource" "foo" { 21 required = "yep" 22 required_map = { 23 key = "value" 24 } 25 } 26 `), 27 Check: func(s *terraform.State) error { 28 return nil 29 }, 30 }, 31 }, 32 }) 33 } 34 35 // Targeted test in TestContext2Apply_ignoreChangesCreate 36 func TestResource_ignoreChangesRequired(t *testing.T) { 37 resource.UnitTest(t, resource.TestCase{ 38 Providers: testAccProviders, 39 CheckDestroy: testAccCheckResourceDestroy, 40 Steps: []resource.TestStep{ 41 resource.TestStep{ 42 Config: strings.TrimSpace(` 43 resource "test_resource" "foo" { 44 required = "yep" 45 required_map = { 46 key = "value" 47 } 48 lifecycle { 49 ignore_changes = ["required"] 50 } 51 } 52 `), 53 Check: func(s *terraform.State) error { 54 return nil 55 }, 56 }, 57 }, 58 }) 59 } 60 61 func TestResource_ignoreChangesEmpty(t *testing.T) { 62 resource.UnitTest(t, resource.TestCase{ 63 Providers: testAccProviders, 64 CheckDestroy: testAccCheckResourceDestroy, 65 Steps: []resource.TestStep{ 66 resource.TestStep{ 67 Config: strings.TrimSpace(` 68 resource "test_resource" "foo" { 69 required = "yep" 70 required_map = { 71 key = "value" 72 } 73 optional_force_new = "one" 74 lifecycle { 75 ignore_changes = [] 76 } 77 } 78 `), 79 Check: func(s *terraform.State) error { 80 return nil 81 }, 82 }, 83 resource.TestStep{ 84 Config: strings.TrimSpace(` 85 resource "test_resource" "foo" { 86 required = "yep" 87 required_map { 88 key = "value" 89 } 90 optional_force_new = "two" 91 lifecycle { 92 ignore_changes = [] 93 } 94 } 95 `), 96 Check: func(s *terraform.State) error { 97 return nil 98 }, 99 }, 100 }, 101 }) 102 } 103 104 func TestResource_ignoreChangesForceNew(t *testing.T) { 105 resource.UnitTest(t, resource.TestCase{ 106 Providers: testAccProviders, 107 CheckDestroy: testAccCheckResourceDestroy, 108 Steps: []resource.TestStep{ 109 resource.TestStep{ 110 Config: strings.TrimSpace(` 111 resource "test_resource" "foo" { 112 required = "yep" 113 required_map { 114 key = "value" 115 } 116 optional_force_new = "one" 117 lifecycle { 118 ignore_changes = ["optional_force_new"] 119 } 120 } 121 `), 122 Check: func(s *terraform.State) error { 123 return nil 124 }, 125 }, 126 resource.TestStep{ 127 Config: strings.TrimSpace(` 128 resource "test_resource" "foo" { 129 required = "yep" 130 required_map = { 131 key = "value" 132 } 133 optional_force_new = "two" 134 lifecycle { 135 ignore_changes = ["optional_force_new"] 136 } 137 } 138 `), 139 Check: func(s *terraform.State) error { 140 return nil 141 }, 142 }, 143 }, 144 }) 145 } 146 147 // Covers specific scenario in #6005, handled by normalizing boolean strings in 148 // helper/schema 149 func TestResource_ignoreChangesForceNewBoolean(t *testing.T) { 150 resource.UnitTest(t, resource.TestCase{ 151 Providers: testAccProviders, 152 CheckDestroy: testAccCheckResourceDestroy, 153 Steps: []resource.TestStep{ 154 resource.TestStep{ 155 Config: strings.TrimSpace(` 156 resource "test_resource" "foo" { 157 required = "yep" 158 required_map = { 159 key = "value" 160 } 161 optional_force_new = "one" 162 optional_bool = true 163 lifecycle { 164 ignore_changes = ["optional_force_new"] 165 } 166 } 167 `), 168 Check: func(s *terraform.State) error { 169 return nil 170 }, 171 }, 172 resource.TestStep{ 173 Config: strings.TrimSpace(` 174 resource "test_resource" "foo" { 175 required = "yep" 176 required_map = { 177 key = "value" 178 } 179 optional_force_new = "two" 180 optional_bool = true 181 lifecycle { 182 ignore_changes = ["optional_force_new"] 183 } 184 } 185 `), 186 Check: func(s *terraform.State) error { 187 return nil 188 }, 189 }, 190 }, 191 }) 192 } 193 194 // Reproduces plan-time panic described in GH-7170 195 func TestResource_dataSourceListPlanPanic(t *testing.T) { 196 resource.UnitTest(t, resource.TestCase{ 197 Providers: testAccProviders, 198 CheckDestroy: testAccCheckResourceDestroy, 199 Steps: []resource.TestStep{ 200 resource.TestStep{ 201 Config: strings.TrimSpace(` 202 data "test_data_source" "foo" {} 203 resource "test_resource" "foo" { 204 required = "${data.test_data_source.foo.list}" 205 required_map = { 206 key = "value" 207 } 208 } 209 `), 210 ExpectError: regexp.MustCompile(`must be a single value, not a list`), 211 Check: func(s *terraform.State) error { 212 return nil 213 }, 214 }, 215 }, 216 }) 217 } 218 219 // Reproduces apply-time panic described in GH-7170 220 func TestResource_dataSourceListApplyPanic(t *testing.T) { 221 resource.UnitTest(t, resource.TestCase{ 222 Providers: testAccProviders, 223 CheckDestroy: testAccCheckResourceDestroy, 224 Steps: []resource.TestStep{ 225 resource.TestStep{ 226 Config: strings.TrimSpace(` 227 resource "test_resource" "foo" { 228 required = "ok" 229 required_map = { 230 key = "value" 231 } 232 } 233 resource "test_resource" "bar" { 234 required = "${test_resource.foo.computed_list}" 235 required_map = { 236 key = "value" 237 } 238 } 239 `), 240 ExpectError: regexp.MustCompile(`must be a single value, not a list`), 241 Check: func(s *terraform.State) error { 242 return nil 243 }, 244 }, 245 }, 246 }) 247 } 248 249 func TestResource_ignoreChangesMap(t *testing.T) { 250 resource.UnitTest(t, resource.TestCase{ 251 Providers: testAccProviders, 252 CheckDestroy: testAccCheckResourceDestroy, 253 Steps: []resource.TestStep{ 254 resource.TestStep{ 255 Config: strings.TrimSpace(` 256 resource "test_resource" "foo" { 257 required = "yep" 258 required_map = { 259 key = "value" 260 } 261 optional_computed_map { 262 foo = "bar" 263 } 264 lifecycle { 265 ignore_changes = ["optional_computed_map"] 266 } 267 } 268 `), 269 Check: func(s *terraform.State) error { 270 return nil 271 }, 272 }, 273 resource.TestStep{ 274 Config: strings.TrimSpace(` 275 resource "test_resource" "foo" { 276 required = "yep" 277 required_map = { 278 key = "value" 279 } 280 optional_computed_map { 281 foo = "bar" 282 no = "update" 283 } 284 lifecycle { 285 ignore_changes = ["optional_computed_map"] 286 } 287 } 288 `), 289 Check: func(s *terraform.State) error { 290 return nil 291 }, 292 }, 293 }, 294 }) 295 } 296 297 func TestResource_ignoreChangesDependent(t *testing.T) { 298 resource.UnitTest(t, resource.TestCase{ 299 Providers: testAccProviders, 300 CheckDestroy: testAccCheckResourceDestroy, 301 Steps: []resource.TestStep{ 302 resource.TestStep{ 303 Config: strings.TrimSpace(` 304 resource "test_resource" "foo" { 305 count = 2 306 required = "yep" 307 required_map { key = "value" } 308 309 optional_force_new = "one" 310 lifecycle { 311 ignore_changes = ["optional_force_new"] 312 } 313 } 314 resource "test_resource" "bar" { 315 count = 2 316 required = "yep" 317 required_map { key = "value" } 318 optional = "${element(test_resource.foo.*.id, count.index)}" 319 } 320 `), 321 Check: func(s *terraform.State) error { 322 return nil 323 }, 324 }, 325 resource.TestStep{ 326 Config: strings.TrimSpace(` 327 resource "test_resource" "foo" { 328 count = 2 329 required = "yep" 330 required_map { key = "value" } 331 332 optional_force_new = "two" 333 lifecycle { 334 ignore_changes = ["optional_force_new"] 335 } 336 } 337 resource "test_resource" "bar" { 338 count = 2 339 required = "yep" 340 required_map { key = "value" } 341 optional = "${element(test_resource.foo.*.id, count.index)}" 342 } 343 `), 344 Check: func(s *terraform.State) error { 345 return nil 346 }, 347 }, 348 }, 349 }) 350 } 351 352 func TestResource_ignoreChangesStillReplaced(t *testing.T) { 353 resource.UnitTest(t, resource.TestCase{ 354 Providers: testAccProviders, 355 CheckDestroy: testAccCheckResourceDestroy, 356 Steps: []resource.TestStep{ 357 resource.TestStep{ 358 Config: strings.TrimSpace(` 359 resource "test_resource" "foo" { 360 required = "yep" 361 required_map = { 362 key = "value" 363 } 364 optional_force_new = "one" 365 optional_bool = true 366 lifecycle { 367 ignore_changes = ["optional_bool"] 368 } 369 } 370 `), 371 Check: func(s *terraform.State) error { 372 return nil 373 }, 374 }, 375 resource.TestStep{ 376 Config: strings.TrimSpace(` 377 resource "test_resource" "foo" { 378 required = "yep" 379 required_map = { 380 key = "value" 381 } 382 optional_force_new = "two" 383 optional_bool = false 384 lifecycle { 385 ignore_changes = ["optional_bool"] 386 } 387 } 388 `), 389 Check: func(s *terraform.State) error { 390 return nil 391 }, 392 }, 393 }, 394 }) 395 } 396 397 // Reproduces plan-time panic when the wrong type is interpolated in a list of 398 // maps. 399 // TODO: this should return a type error, rather than silently setting an empty 400 // list 401 func TestResource_dataSourceListMapPanic(t *testing.T) { 402 resource.UnitTest(t, resource.TestCase{ 403 Providers: testAccProviders, 404 CheckDestroy: testAccCheckResourceDestroy, 405 Steps: []resource.TestStep{ 406 resource.TestStep{ 407 Config: strings.TrimSpace(` 408 resource "test_resource" "foo" { 409 required = "val" 410 required_map = {x = "y"} 411 list_of_map = "${var.maplist}" 412 } 413 414 variable "maplist" { 415 type = "list" 416 417 default = [ 418 {a = "b"} 419 ] 420 } 421 `), 422 ExpectError: nil, 423 Check: func(s *terraform.State) error { 424 return nil 425 }, 426 }, 427 }, 428 }) 429 } 430 431 func TestResource_dataSourceIndexMapList(t *testing.T) { 432 resource.UnitTest(t, resource.TestCase{ 433 Providers: testAccProviders, 434 CheckDestroy: testAccCheckResourceDestroy, 435 Steps: []resource.TestStep{ 436 resource.TestStep{ 437 Config: strings.TrimSpace(` 438 resource "test_resource" "foo" { 439 required = "val" 440 441 required_map = { 442 x = "y" 443 } 444 445 list_of_map = [ 446 { 447 a = "1" 448 b = "2" 449 }, 450 { 451 c = "3" 452 d = "4" 453 }, 454 ] 455 } 456 457 output "map_from_list" { 458 value = "${test_resource.foo.list_of_map[0]}" 459 } 460 461 output "value_from_map_from_list" { 462 value = "${lookup(test_resource.foo.list_of_map[1], "d")}" 463 } 464 `), 465 ExpectError: nil, 466 Check: func(s *terraform.State) error { 467 root := s.ModuleByPath(terraform.RootModulePath) 468 mapOut := root.Outputs["map_from_list"].Value 469 expectedMapOut := map[string]interface{}{ 470 "a": "1", 471 "b": "2", 472 } 473 474 valueOut := root.Outputs["value_from_map_from_list"].Value 475 expectedValueOut := "4" 476 477 if !reflect.DeepEqual(mapOut, expectedMapOut) { 478 t.Fatalf("Expected: %#v\nGot: %#v", expectedMapOut, mapOut) 479 } 480 if !reflect.DeepEqual(valueOut, expectedValueOut) { 481 t.Fatalf("Expected: %#v\nGot: %#v", valueOut, expectedValueOut) 482 } 483 return nil 484 }, 485 }, 486 }, 487 }) 488 } 489 490 func testAccCheckResourceDestroy(s *terraform.State) error { 491 return nil 492 }