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