github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/aws/structure_test.go (about) 1 package aws 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 8 "github.com/aws/aws-sdk-go/aws" 9 "github.com/aws/aws-sdk-go/service/apigateway" 10 "github.com/aws/aws-sdk-go/service/autoscaling" 11 "github.com/aws/aws-sdk-go/service/ec2" 12 "github.com/aws/aws-sdk-go/service/elasticache" 13 "github.com/aws/aws-sdk-go/service/elb" 14 "github.com/aws/aws-sdk-go/service/kinesis" 15 "github.com/aws/aws-sdk-go/service/rds" 16 "github.com/aws/aws-sdk-go/service/redshift" 17 "github.com/aws/aws-sdk-go/service/route53" 18 "github.com/hashicorp/terraform/flatmap" 19 "github.com/hashicorp/terraform/helper/schema" 20 ) 21 22 // Returns test configuration 23 func testConf() map[string]string { 24 return map[string]string{ 25 "listener.#": "1", 26 "listener.0.lb_port": "80", 27 "listener.0.lb_protocol": "http", 28 "listener.0.instance_port": "8000", 29 "listener.0.instance_protocol": "http", 30 "availability_zones.#": "2", 31 "availability_zones.0": "us-east-1a", 32 "availability_zones.1": "us-east-1b", 33 "ingress.#": "1", 34 "ingress.0.protocol": "icmp", 35 "ingress.0.from_port": "1", 36 "ingress.0.to_port": "-1", 37 "ingress.0.cidr_blocks.#": "1", 38 "ingress.0.cidr_blocks.0": "0.0.0.0/0", 39 "ingress.0.security_groups.#": "2", 40 "ingress.0.security_groups.0": "sg-11111", 41 "ingress.0.security_groups.1": "foo/sg-22222", 42 } 43 } 44 45 func TestExpandIPPerms(t *testing.T) { 46 hash := schema.HashString 47 48 expanded := []interface{}{ 49 map[string]interface{}{ 50 "protocol": "icmp", 51 "from_port": 1, 52 "to_port": -1, 53 "cidr_blocks": []interface{}{"0.0.0.0/0"}, 54 "security_groups": schema.NewSet(hash, []interface{}{ 55 "sg-11111", 56 "foo/sg-22222", 57 }), 58 }, 59 map[string]interface{}{ 60 "protocol": "icmp", 61 "from_port": 1, 62 "to_port": -1, 63 "self": true, 64 }, 65 } 66 group := &ec2.SecurityGroup{ 67 GroupId: aws.String("foo"), 68 VpcId: aws.String("bar"), 69 } 70 perms, err := expandIPPerms(group, expanded) 71 if err != nil { 72 t.Fatalf("error expanding perms: %v", err) 73 } 74 75 expected := []ec2.IpPermission{ 76 ec2.IpPermission{ 77 IpProtocol: aws.String("icmp"), 78 FromPort: aws.Int64(int64(1)), 79 ToPort: aws.Int64(int64(-1)), 80 IpRanges: []*ec2.IpRange{&ec2.IpRange{CidrIp: aws.String("0.0.0.0/0")}}, 81 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 82 &ec2.UserIdGroupPair{ 83 UserId: aws.String("foo"), 84 GroupId: aws.String("sg-22222"), 85 }, 86 &ec2.UserIdGroupPair{ 87 GroupId: aws.String("sg-11111"), 88 }, 89 }, 90 }, 91 ec2.IpPermission{ 92 IpProtocol: aws.String("icmp"), 93 FromPort: aws.Int64(int64(1)), 94 ToPort: aws.Int64(int64(-1)), 95 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 96 &ec2.UserIdGroupPair{ 97 GroupId: aws.String("foo"), 98 }, 99 }, 100 }, 101 } 102 103 exp := expected[0] 104 perm := perms[0] 105 106 if *exp.FromPort != *perm.FromPort { 107 t.Fatalf( 108 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 109 *perm.FromPort, 110 *exp.FromPort) 111 } 112 113 if *exp.IpRanges[0].CidrIp != *perm.IpRanges[0].CidrIp { 114 t.Fatalf( 115 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 116 *perm.IpRanges[0].CidrIp, 117 *exp.IpRanges[0].CidrIp) 118 } 119 120 if *exp.UserIdGroupPairs[0].UserId != *perm.UserIdGroupPairs[0].UserId { 121 t.Fatalf( 122 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 123 *perm.UserIdGroupPairs[0].UserId, 124 *exp.UserIdGroupPairs[0].UserId) 125 } 126 127 if *exp.UserIdGroupPairs[0].GroupId != *perm.UserIdGroupPairs[0].GroupId { 128 t.Fatalf( 129 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 130 *perm.UserIdGroupPairs[0].GroupId, 131 *exp.UserIdGroupPairs[0].GroupId) 132 } 133 134 if *exp.UserIdGroupPairs[1].GroupId != *perm.UserIdGroupPairs[1].GroupId { 135 t.Fatalf( 136 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 137 *perm.UserIdGroupPairs[1].GroupId, 138 *exp.UserIdGroupPairs[1].GroupId) 139 } 140 141 exp = expected[1] 142 perm = perms[1] 143 144 if *exp.UserIdGroupPairs[0].GroupId != *perm.UserIdGroupPairs[0].GroupId { 145 t.Fatalf( 146 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 147 *perm.UserIdGroupPairs[0].GroupId, 148 *exp.UserIdGroupPairs[0].GroupId) 149 } 150 } 151 152 func TestExpandIPPerms_NegOneProtocol(t *testing.T) { 153 hash := schema.HashString 154 155 expanded := []interface{}{ 156 map[string]interface{}{ 157 "protocol": "-1", 158 "from_port": 0, 159 "to_port": 0, 160 "cidr_blocks": []interface{}{"0.0.0.0/0"}, 161 "security_groups": schema.NewSet(hash, []interface{}{ 162 "sg-11111", 163 "foo/sg-22222", 164 }), 165 }, 166 } 167 group := &ec2.SecurityGroup{ 168 GroupId: aws.String("foo"), 169 VpcId: aws.String("bar"), 170 } 171 172 perms, err := expandIPPerms(group, expanded) 173 if err != nil { 174 t.Fatalf("error expanding perms: %v", err) 175 } 176 177 expected := []ec2.IpPermission{ 178 ec2.IpPermission{ 179 IpProtocol: aws.String("-1"), 180 FromPort: aws.Int64(int64(0)), 181 ToPort: aws.Int64(int64(0)), 182 IpRanges: []*ec2.IpRange{&ec2.IpRange{CidrIp: aws.String("0.0.0.0/0")}}, 183 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 184 &ec2.UserIdGroupPair{ 185 UserId: aws.String("foo"), 186 GroupId: aws.String("sg-22222"), 187 }, 188 &ec2.UserIdGroupPair{ 189 GroupId: aws.String("sg-11111"), 190 }, 191 }, 192 }, 193 } 194 195 exp := expected[0] 196 perm := perms[0] 197 198 if *exp.FromPort != *perm.FromPort { 199 t.Fatalf( 200 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 201 *perm.FromPort, 202 *exp.FromPort) 203 } 204 205 if *exp.IpRanges[0].CidrIp != *perm.IpRanges[0].CidrIp { 206 t.Fatalf( 207 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 208 *perm.IpRanges[0].CidrIp, 209 *exp.IpRanges[0].CidrIp) 210 } 211 212 if *exp.UserIdGroupPairs[0].UserId != *perm.UserIdGroupPairs[0].UserId { 213 t.Fatalf( 214 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 215 *perm.UserIdGroupPairs[0].UserId, 216 *exp.UserIdGroupPairs[0].UserId) 217 } 218 219 // Now test the error case. This *should* error when either from_port 220 // or to_port is not zero, but protocol is "-1". 221 errorCase := []interface{}{ 222 map[string]interface{}{ 223 "protocol": "-1", 224 "from_port": 0, 225 "to_port": 65535, 226 "cidr_blocks": []interface{}{"0.0.0.0/0"}, 227 "security_groups": schema.NewSet(hash, []interface{}{ 228 "sg-11111", 229 "foo/sg-22222", 230 }), 231 }, 232 } 233 securityGroups := &ec2.SecurityGroup{ 234 GroupId: aws.String("foo"), 235 VpcId: aws.String("bar"), 236 } 237 238 _, expandErr := expandIPPerms(securityGroups, errorCase) 239 if expandErr == nil { 240 t.Fatal("expandIPPerms should have errored!") 241 } 242 } 243 244 func TestExpandIPPerms_nonVPC(t *testing.T) { 245 hash := schema.HashString 246 247 expanded := []interface{}{ 248 map[string]interface{}{ 249 "protocol": "icmp", 250 "from_port": 1, 251 "to_port": -1, 252 "cidr_blocks": []interface{}{"0.0.0.0/0"}, 253 "security_groups": schema.NewSet(hash, []interface{}{ 254 "sg-11111", 255 "foo/sg-22222", 256 }), 257 }, 258 map[string]interface{}{ 259 "protocol": "icmp", 260 "from_port": 1, 261 "to_port": -1, 262 "self": true, 263 }, 264 } 265 group := &ec2.SecurityGroup{ 266 GroupName: aws.String("foo"), 267 } 268 perms, err := expandIPPerms(group, expanded) 269 if err != nil { 270 t.Fatalf("error expanding perms: %v", err) 271 } 272 273 expected := []ec2.IpPermission{ 274 ec2.IpPermission{ 275 IpProtocol: aws.String("icmp"), 276 FromPort: aws.Int64(int64(1)), 277 ToPort: aws.Int64(int64(-1)), 278 IpRanges: []*ec2.IpRange{&ec2.IpRange{CidrIp: aws.String("0.0.0.0/0")}}, 279 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 280 &ec2.UserIdGroupPair{ 281 GroupName: aws.String("sg-22222"), 282 }, 283 &ec2.UserIdGroupPair{ 284 GroupName: aws.String("sg-11111"), 285 }, 286 }, 287 }, 288 ec2.IpPermission{ 289 IpProtocol: aws.String("icmp"), 290 FromPort: aws.Int64(int64(1)), 291 ToPort: aws.Int64(int64(-1)), 292 UserIdGroupPairs: []*ec2.UserIdGroupPair{ 293 &ec2.UserIdGroupPair{ 294 GroupName: aws.String("foo"), 295 }, 296 }, 297 }, 298 } 299 300 exp := expected[0] 301 perm := perms[0] 302 303 if *exp.FromPort != *perm.FromPort { 304 t.Fatalf( 305 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 306 *perm.FromPort, 307 *exp.FromPort) 308 } 309 310 if *exp.IpRanges[0].CidrIp != *perm.IpRanges[0].CidrIp { 311 t.Fatalf( 312 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 313 *perm.IpRanges[0].CidrIp, 314 *exp.IpRanges[0].CidrIp) 315 } 316 317 if *exp.UserIdGroupPairs[0].GroupName != *perm.UserIdGroupPairs[0].GroupName { 318 t.Fatalf( 319 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 320 *perm.UserIdGroupPairs[0].GroupName, 321 *exp.UserIdGroupPairs[0].GroupName) 322 } 323 324 if *exp.UserIdGroupPairs[1].GroupName != *perm.UserIdGroupPairs[1].GroupName { 325 t.Fatalf( 326 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 327 *perm.UserIdGroupPairs[1].GroupName, 328 *exp.UserIdGroupPairs[1].GroupName) 329 } 330 331 exp = expected[1] 332 perm = perms[1] 333 334 if *exp.UserIdGroupPairs[0].GroupName != *perm.UserIdGroupPairs[0].GroupName { 335 t.Fatalf( 336 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 337 *perm.UserIdGroupPairs[0].GroupName, 338 *exp.UserIdGroupPairs[0].GroupName) 339 } 340 } 341 342 func TestExpandListeners(t *testing.T) { 343 expanded := []interface{}{ 344 map[string]interface{}{ 345 "instance_port": 8000, 346 "lb_port": 80, 347 "instance_protocol": "http", 348 "lb_protocol": "http", 349 }, 350 map[string]interface{}{ 351 "instance_port": 8000, 352 "lb_port": 80, 353 "instance_protocol": "https", 354 "lb_protocol": "https", 355 "ssl_certificate_id": "something", 356 }, 357 } 358 listeners, err := expandListeners(expanded) 359 if err != nil { 360 t.Fatalf("bad: %#v", err) 361 } 362 363 expected := &elb.Listener{ 364 InstancePort: aws.Int64(int64(8000)), 365 LoadBalancerPort: aws.Int64(int64(80)), 366 InstanceProtocol: aws.String("http"), 367 Protocol: aws.String("http"), 368 } 369 370 if !reflect.DeepEqual(listeners[0], expected) { 371 t.Fatalf( 372 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 373 listeners[0], 374 expected) 375 } 376 } 377 378 // this test should produce an error from expandlisteners on an invalid 379 // combination 380 func TestExpandListeners_invalid(t *testing.T) { 381 expanded := []interface{}{ 382 map[string]interface{}{ 383 "instance_port": 8000, 384 "lb_port": 80, 385 "instance_protocol": "http", 386 "lb_protocol": "http", 387 "ssl_certificate_id": "something", 388 }, 389 } 390 _, err := expandListeners(expanded) 391 if err != nil { 392 // Check the error we got 393 if !strings.Contains(err.Error(), "ssl_certificate_id may be set only when protocol") { 394 t.Fatalf("Got error in TestExpandListeners_invalid, but not what we expected: %s", err) 395 } 396 } 397 398 if err == nil { 399 t.Fatalf("Expected TestExpandListeners_invalid to fail, but passed") 400 } 401 } 402 403 func TestFlattenHealthCheck(t *testing.T) { 404 cases := []struct { 405 Input *elb.HealthCheck 406 Output []map[string]interface{} 407 }{ 408 { 409 Input: &elb.HealthCheck{ 410 UnhealthyThreshold: aws.Int64(int64(10)), 411 HealthyThreshold: aws.Int64(int64(10)), 412 Target: aws.String("HTTP:80/"), 413 Timeout: aws.Int64(int64(30)), 414 Interval: aws.Int64(int64(30)), 415 }, 416 Output: []map[string]interface{}{ 417 map[string]interface{}{ 418 "unhealthy_threshold": int64(10), 419 "healthy_threshold": int64(10), 420 "target": "HTTP:80/", 421 "timeout": int64(30), 422 "interval": int64(30), 423 }, 424 }, 425 }, 426 } 427 428 for _, tc := range cases { 429 output := flattenHealthCheck(tc.Input) 430 if !reflect.DeepEqual(output, tc.Output) { 431 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 432 } 433 } 434 } 435 436 func TestExpandStringList(t *testing.T) { 437 expanded := flatmap.Expand(testConf(), "availability_zones").([]interface{}) 438 stringList := expandStringList(expanded) 439 expected := []*string{ 440 aws.String("us-east-1a"), 441 aws.String("us-east-1b"), 442 } 443 444 if !reflect.DeepEqual(stringList, expected) { 445 t.Fatalf( 446 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 447 stringList, 448 expected) 449 } 450 } 451 452 func TestExpandStringListEmptyItems(t *testing.T) { 453 initialList := []string{"foo", "bar", "", "baz"} 454 l := make([]interface{}, len(initialList)) 455 for i, v := range initialList { 456 l[i] = v 457 } 458 stringList := expandStringList(l) 459 expected := []*string{ 460 aws.String("foo"), 461 aws.String("bar"), 462 aws.String("baz"), 463 } 464 465 if !reflect.DeepEqual(stringList, expected) { 466 t.Fatalf( 467 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 468 stringList, 469 expected) 470 } 471 } 472 473 func TestExpandParameters(t *testing.T) { 474 expanded := []interface{}{ 475 map[string]interface{}{ 476 "name": "character_set_client", 477 "value": "utf8", 478 "apply_method": "immediate", 479 }, 480 } 481 parameters, err := expandParameters(expanded) 482 if err != nil { 483 t.Fatalf("bad: %#v", err) 484 } 485 486 expected := &rds.Parameter{ 487 ParameterName: aws.String("character_set_client"), 488 ParameterValue: aws.String("utf8"), 489 ApplyMethod: aws.String("immediate"), 490 } 491 492 if !reflect.DeepEqual(parameters[0], expected) { 493 t.Fatalf( 494 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 495 parameters[0], 496 expected) 497 } 498 } 499 500 func TestExpandRedshiftParameters(t *testing.T) { 501 expanded := []interface{}{ 502 map[string]interface{}{ 503 "name": "character_set_client", 504 "value": "utf8", 505 }, 506 } 507 parameters, err := expandRedshiftParameters(expanded) 508 if err != nil { 509 t.Fatalf("bad: %#v", err) 510 } 511 512 expected := &redshift.Parameter{ 513 ParameterName: aws.String("character_set_client"), 514 ParameterValue: aws.String("utf8"), 515 } 516 517 if !reflect.DeepEqual(parameters[0], expected) { 518 t.Fatalf( 519 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 520 parameters[0], 521 expected) 522 } 523 } 524 525 func TestExpandElasticacheParameters(t *testing.T) { 526 expanded := []interface{}{ 527 map[string]interface{}{ 528 "name": "activerehashing", 529 "value": "yes", 530 "apply_method": "immediate", 531 }, 532 } 533 parameters, err := expandElastiCacheParameters(expanded) 534 if err != nil { 535 t.Fatalf("bad: %#v", err) 536 } 537 538 expected := &elasticache.ParameterNameValue{ 539 ParameterName: aws.String("activerehashing"), 540 ParameterValue: aws.String("yes"), 541 } 542 543 if !reflect.DeepEqual(parameters[0], expected) { 544 t.Fatalf( 545 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 546 parameters[0], 547 expected) 548 } 549 } 550 551 func TestExpandStepAdjustments(t *testing.T) { 552 expanded := []interface{}{ 553 map[string]interface{}{ 554 "metric_interval_lower_bound": "1.0", 555 "metric_interval_upper_bound": "2.0", 556 "scaling_adjustment": 1, 557 }, 558 } 559 parameters, err := expandStepAdjustments(expanded) 560 if err != nil { 561 t.Fatalf("bad: %#v", err) 562 } 563 564 expected := &autoscaling.StepAdjustment{ 565 MetricIntervalLowerBound: aws.Float64(1.0), 566 MetricIntervalUpperBound: aws.Float64(2.0), 567 ScalingAdjustment: aws.Int64(int64(1)), 568 } 569 570 if !reflect.DeepEqual(parameters[0], expected) { 571 t.Fatalf( 572 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 573 parameters[0], 574 expected) 575 } 576 } 577 578 func TestFlattenParameters(t *testing.T) { 579 cases := []struct { 580 Input []*rds.Parameter 581 Output []map[string]interface{} 582 }{ 583 { 584 Input: []*rds.Parameter{ 585 &rds.Parameter{ 586 ParameterName: aws.String("character_set_client"), 587 ParameterValue: aws.String("utf8"), 588 }, 589 }, 590 Output: []map[string]interface{}{ 591 map[string]interface{}{ 592 "name": "character_set_client", 593 "value": "utf8", 594 }, 595 }, 596 }, 597 } 598 599 for _, tc := range cases { 600 output := flattenParameters(tc.Input) 601 if !reflect.DeepEqual(output, tc.Output) { 602 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 603 } 604 } 605 } 606 607 func TestFlattenRedshiftParameters(t *testing.T) { 608 cases := []struct { 609 Input []*redshift.Parameter 610 Output []map[string]interface{} 611 }{ 612 { 613 Input: []*redshift.Parameter{ 614 &redshift.Parameter{ 615 ParameterName: aws.String("character_set_client"), 616 ParameterValue: aws.String("utf8"), 617 }, 618 }, 619 Output: []map[string]interface{}{ 620 map[string]interface{}{ 621 "name": "character_set_client", 622 "value": "utf8", 623 }, 624 }, 625 }, 626 } 627 628 for _, tc := range cases { 629 output := flattenRedshiftParameters(tc.Input) 630 if !reflect.DeepEqual(output, tc.Output) { 631 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 632 } 633 } 634 } 635 636 func TestFlattenElasticacheParameters(t *testing.T) { 637 cases := []struct { 638 Input []*elasticache.Parameter 639 Output []map[string]interface{} 640 }{ 641 { 642 Input: []*elasticache.Parameter{ 643 &elasticache.Parameter{ 644 ParameterName: aws.String("activerehashing"), 645 ParameterValue: aws.String("yes"), 646 }, 647 }, 648 Output: []map[string]interface{}{ 649 map[string]interface{}{ 650 "name": "activerehashing", 651 "value": "yes", 652 }, 653 }, 654 }, 655 } 656 657 for _, tc := range cases { 658 output := flattenElastiCacheParameters(tc.Input) 659 if !reflect.DeepEqual(output, tc.Output) { 660 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 661 } 662 } 663 } 664 665 func TestExpandInstanceString(t *testing.T) { 666 667 expected := []*elb.Instance{ 668 &elb.Instance{InstanceId: aws.String("test-one")}, 669 &elb.Instance{InstanceId: aws.String("test-two")}, 670 } 671 672 ids := []interface{}{ 673 "test-one", 674 "test-two", 675 } 676 677 expanded := expandInstanceString(ids) 678 679 if !reflect.DeepEqual(expanded, expected) { 680 t.Fatalf("Expand Instance String output did not match.\nGot:\n%#v\n\nexpected:\n%#v", expanded, expected) 681 } 682 } 683 684 func TestFlattenNetworkInterfacesPrivateIPAddresses(t *testing.T) { 685 expanded := []*ec2.NetworkInterfacePrivateIpAddress{ 686 &ec2.NetworkInterfacePrivateIpAddress{PrivateIpAddress: aws.String("192.168.0.1")}, 687 &ec2.NetworkInterfacePrivateIpAddress{PrivateIpAddress: aws.String("192.168.0.2")}, 688 } 689 690 result := flattenNetworkInterfacesPrivateIPAddresses(expanded) 691 692 if result == nil { 693 t.Fatal("result was nil") 694 } 695 696 if len(result) != 2 { 697 t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) 698 } 699 700 if result[0] != "192.168.0.1" { 701 t.Fatalf("expected ip to be 192.168.0.1, but was %s", result[0]) 702 } 703 704 if result[1] != "192.168.0.2" { 705 t.Fatalf("expected ip to be 192.168.0.2, but was %s", result[1]) 706 } 707 } 708 709 func TestFlattenGroupIdentifiers(t *testing.T) { 710 expanded := []*ec2.GroupIdentifier{ 711 &ec2.GroupIdentifier{GroupId: aws.String("sg-001")}, 712 &ec2.GroupIdentifier{GroupId: aws.String("sg-002")}, 713 } 714 715 result := flattenGroupIdentifiers(expanded) 716 717 if len(result) != 2 { 718 t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) 719 } 720 721 if result[0] != "sg-001" { 722 t.Fatalf("expected id to be sg-001, but was %s", result[0]) 723 } 724 725 if result[1] != "sg-002" { 726 t.Fatalf("expected id to be sg-002, but was %s", result[1]) 727 } 728 } 729 730 func TestExpandPrivateIPAddresses(t *testing.T) { 731 732 ip1 := "192.168.0.1" 733 ip2 := "192.168.0.2" 734 flattened := []interface{}{ 735 ip1, 736 ip2, 737 } 738 739 result := expandPrivateIPAddresses(flattened) 740 741 if len(result) != 2 { 742 t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) 743 } 744 745 if *result[0].PrivateIpAddress != "192.168.0.1" || !*result[0].Primary { 746 t.Fatalf("expected ip to be 192.168.0.1 and Primary, but got %v, %t", *result[0].PrivateIpAddress, *result[0].Primary) 747 } 748 749 if *result[1].PrivateIpAddress != "192.168.0.2" || *result[1].Primary { 750 t.Fatalf("expected ip to be 192.168.0.2 and not Primary, but got %v, %t", *result[1].PrivateIpAddress, *result[1].Primary) 751 } 752 } 753 754 func TestFlattenAttachment(t *testing.T) { 755 expanded := &ec2.NetworkInterfaceAttachment{ 756 InstanceId: aws.String("i-00001"), 757 DeviceIndex: aws.Int64(int64(1)), 758 AttachmentId: aws.String("at-002"), 759 } 760 761 result := flattenAttachment(expanded) 762 763 if result == nil { 764 t.Fatal("expected result to have value, but got nil") 765 } 766 767 if result["instance"] != "i-00001" { 768 t.Fatalf("expected instance to be i-00001, but got %s", result["instance"]) 769 } 770 771 if result["device_index"] != int64(1) { 772 t.Fatalf("expected device_index to be 1, but got %d", result["device_index"]) 773 } 774 775 if result["attachment_id"] != "at-002" { 776 t.Fatalf("expected attachment_id to be at-002, but got %s", result["attachment_id"]) 777 } 778 } 779 780 func TestFlattenAttachmentWhenNoInstanceId(t *testing.T) { 781 expanded := &ec2.NetworkInterfaceAttachment{ 782 DeviceIndex: aws.Int64(int64(1)), 783 AttachmentId: aws.String("at-002"), 784 } 785 786 result := flattenAttachment(expanded) 787 788 if result == nil { 789 t.Fatal("expected result to have value, but got nil") 790 } 791 792 if result["instance"] != nil { 793 t.Fatalf("expected instance to be nil, but got %s", result["instance"]) 794 } 795 } 796 797 func TestFlattenStepAdjustments(t *testing.T) { 798 expanded := []*autoscaling.StepAdjustment{ 799 &autoscaling.StepAdjustment{ 800 MetricIntervalLowerBound: aws.Float64(1.0), 801 MetricIntervalUpperBound: aws.Float64(2.0), 802 ScalingAdjustment: aws.Int64(int64(1)), 803 }, 804 } 805 806 result := flattenStepAdjustments(expanded)[0] 807 if result == nil { 808 t.Fatal("expected result to have value, but got nil") 809 } 810 if result["metric_interval_lower_bound"] != float64(1.0) { 811 t.Fatalf("expected metric_interval_lower_bound to be 1.0, but got %d", result["metric_interval_lower_bound"]) 812 } 813 if result["metric_interval_upper_bound"] != float64(2.0) { 814 t.Fatalf("expected metric_interval_upper_bound to be 1.0, but got %d", result["metric_interval_upper_bound"]) 815 } 816 if result["scaling_adjustment"] != int64(1) { 817 t.Fatalf("expected scaling_adjustment to be 1, but got %d", result["scaling_adjustment"]) 818 } 819 } 820 821 func TestFlattenResourceRecords(t *testing.T) { 822 original := []string{ 823 `127.0.0.1`, 824 `"abc def"`, 825 `"abc" "def"`, 826 `"abc" ""`, 827 } 828 829 dequoted := []string{ 830 `127.0.0.1`, 831 `abc def`, 832 `abc" "def`, 833 `abc" "`, 834 } 835 836 var wrapped []*route53.ResourceRecord = nil 837 for _, original := range original { 838 wrapped = append(wrapped, &route53.ResourceRecord{Value: aws.String(original)}) 839 } 840 841 sub := func(recordType string, expected []string) { 842 t.Run(recordType, func(t *testing.T) { 843 checkFlattenResourceRecords(t, recordType, wrapped, expected) 844 }) 845 } 846 847 // These record types should be dequoted. 848 sub("TXT", dequoted) 849 sub("SPF", dequoted) 850 851 // These record types should not be touched. 852 sub("CNAME", original) 853 sub("MX", original) 854 } 855 856 func checkFlattenResourceRecords( 857 t *testing.T, 858 recordType string, 859 expanded []*route53.ResourceRecord, 860 expected []string) { 861 862 result := flattenResourceRecords(expanded, recordType) 863 864 if result == nil { 865 t.Fatal("expected result to have value, but got nil") 866 } 867 868 if len(result) != len(expected) { 869 t.Fatalf("expected %v, got %v", expected, result) 870 } 871 872 for i, e := range expected { 873 if result[i] != e { 874 t.Fatalf("expected %v, got %v", expected, result) 875 } 876 } 877 } 878 879 func TestFlattenAsgEnabledMetrics(t *testing.T) { 880 expanded := []*autoscaling.EnabledMetric{ 881 &autoscaling.EnabledMetric{Granularity: aws.String("1Minute"), Metric: aws.String("GroupTotalInstances")}, 882 &autoscaling.EnabledMetric{Granularity: aws.String("1Minute"), Metric: aws.String("GroupMaxSize")}, 883 } 884 885 result := flattenAsgEnabledMetrics(expanded) 886 887 if len(result) != 2 { 888 t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) 889 } 890 891 if result[0] != "GroupTotalInstances" { 892 t.Fatalf("expected id to be GroupTotalInstances, but was %s", result[0]) 893 } 894 895 if result[1] != "GroupMaxSize" { 896 t.Fatalf("expected id to be GroupMaxSize, but was %s", result[1]) 897 } 898 } 899 900 func TestFlattenKinesisShardLevelMetrics(t *testing.T) { 901 expanded := []*kinesis.EnhancedMetrics{ 902 &kinesis.EnhancedMetrics{ 903 ShardLevelMetrics: []*string{ 904 aws.String("IncomingBytes"), 905 aws.String("IncomingRecords"), 906 }, 907 }, 908 } 909 result := flattenKinesisShardLevelMetrics(expanded) 910 if len(result) != 2 { 911 t.Fatalf("expected result had %d elements, but got %d", 2, len(result)) 912 } 913 if result[0] != "IncomingBytes" { 914 t.Fatalf("expected element 0 to be IncomingBytes, but was %s", result[0]) 915 } 916 if result[1] != "IncomingRecords" { 917 t.Fatalf("expected element 0 to be IncomingRecords, but was %s", result[1]) 918 } 919 } 920 921 func TestFlattenSecurityGroups(t *testing.T) { 922 cases := []struct { 923 ownerId *string 924 pairs []*ec2.UserIdGroupPair 925 expected []*ec2.GroupIdentifier 926 }{ 927 // simple, no user id included (we ignore it mostly) 928 { 929 ownerId: aws.String("user1234"), 930 pairs: []*ec2.UserIdGroupPair{ 931 &ec2.UserIdGroupPair{ 932 GroupId: aws.String("sg-12345"), 933 }, 934 }, 935 expected: []*ec2.GroupIdentifier{ 936 &ec2.GroupIdentifier{ 937 GroupId: aws.String("sg-12345"), 938 }, 939 }, 940 }, 941 // include the owner id, but keep it consitent with the same account. Tests 942 // EC2 classic situation 943 { 944 ownerId: aws.String("user1234"), 945 pairs: []*ec2.UserIdGroupPair{ 946 &ec2.UserIdGroupPair{ 947 GroupId: aws.String("sg-12345"), 948 UserId: aws.String("user1234"), 949 }, 950 }, 951 expected: []*ec2.GroupIdentifier{ 952 &ec2.GroupIdentifier{ 953 GroupId: aws.String("sg-12345"), 954 }, 955 }, 956 }, 957 958 // include the owner id, but from a different account. This is reflects 959 // EC2 Classic when referring to groups by name 960 { 961 ownerId: aws.String("user1234"), 962 pairs: []*ec2.UserIdGroupPair{ 963 &ec2.UserIdGroupPair{ 964 GroupId: aws.String("sg-12345"), 965 GroupName: aws.String("somegroup"), // GroupName is only included in Classic 966 UserId: aws.String("user4321"), 967 }, 968 }, 969 expected: []*ec2.GroupIdentifier{ 970 &ec2.GroupIdentifier{ 971 GroupId: aws.String("sg-12345"), 972 GroupName: aws.String("user4321/somegroup"), 973 }, 974 }, 975 }, 976 977 // include the owner id, but from a different account. This reflects in 978 // EC2 VPC when referring to groups by id 979 { 980 ownerId: aws.String("user1234"), 981 pairs: []*ec2.UserIdGroupPair{ 982 &ec2.UserIdGroupPair{ 983 GroupId: aws.String("sg-12345"), 984 UserId: aws.String("user4321"), 985 }, 986 }, 987 expected: []*ec2.GroupIdentifier{ 988 &ec2.GroupIdentifier{ 989 GroupId: aws.String("user4321/sg-12345"), 990 }, 991 }, 992 }, 993 } 994 995 for _, c := range cases { 996 out := flattenSecurityGroups(c.pairs, c.ownerId) 997 if !reflect.DeepEqual(out, c.expected) { 998 t.Fatalf("Error matching output and expected: %#v vs %#v", out, c.expected) 999 } 1000 } 1001 } 1002 1003 func TestFlattenApiGatewayThrottleSettings(t *testing.T) { 1004 expectedBurstLimit := int64(140) 1005 expectedRateLimit := 120.0 1006 1007 ts := &apigateway.ThrottleSettings{ 1008 BurstLimit: aws.Int64(expectedBurstLimit), 1009 RateLimit: aws.Float64(expectedRateLimit), 1010 } 1011 result := flattenApiGatewayThrottleSettings(ts) 1012 1013 if len(result) != 1 { 1014 t.Fatalf("Expected map to have exactly 1 element, got %d", len(result)) 1015 } 1016 1017 burstLimit, ok := result[0]["burst_limit"] 1018 if !ok { 1019 t.Fatal("Expected 'burst_limit' key in the map") 1020 } 1021 burstLimitInt, ok := burstLimit.(int64) 1022 if !ok { 1023 t.Fatal("Expected 'burst_limit' to be int") 1024 } 1025 if burstLimitInt != expectedBurstLimit { 1026 t.Fatalf("Expected 'burst_limit' to equal %d, got %d", expectedBurstLimit, burstLimitInt) 1027 } 1028 1029 rateLimit, ok := result[0]["rate_limit"] 1030 if !ok { 1031 t.Fatal("Expected 'rate_limit' key in the map") 1032 } 1033 rateLimitFloat, ok := rateLimit.(float64) 1034 if !ok { 1035 t.Fatal("Expected 'rate_limit' to be float64") 1036 } 1037 if rateLimitFloat != expectedRateLimit { 1038 t.Fatalf("Expected 'rate_limit' to equal %f, got %f", expectedRateLimit, rateLimitFloat) 1039 } 1040 } 1041 1042 func TestFlattenApiGatewayStageKeys(t *testing.T) { 1043 cases := []struct { 1044 Input []*string 1045 Output []map[string]interface{} 1046 }{ 1047 { 1048 Input: []*string{ 1049 aws.String("a1b2c3d4e5/dev"), 1050 aws.String("e5d4c3b2a1/test"), 1051 }, 1052 Output: []map[string]interface{}{ 1053 map[string]interface{}{ 1054 "stage_name": "dev", 1055 "rest_api_id": "a1b2c3d4e5", 1056 }, 1057 map[string]interface{}{ 1058 "stage_name": "test", 1059 "rest_api_id": "e5d4c3b2a1", 1060 }, 1061 }, 1062 }, 1063 } 1064 1065 for _, tc := range cases { 1066 output := flattenApiGatewayStageKeys(tc.Input) 1067 if !reflect.DeepEqual(output, tc.Output) { 1068 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 1069 } 1070 } 1071 } 1072 1073 func TestExpandPolicyAttributes(t *testing.T) { 1074 expanded := []interface{}{ 1075 map[string]interface{}{ 1076 "name": "Protocol-TLSv1", 1077 "value": "false", 1078 }, 1079 map[string]interface{}{ 1080 "name": "Protocol-TLSv1.1", 1081 "value": "false", 1082 }, 1083 map[string]interface{}{ 1084 "name": "Protocol-TLSv1.2", 1085 "value": "true", 1086 }, 1087 } 1088 attributes, err := expandPolicyAttributes(expanded) 1089 if err != nil { 1090 t.Fatalf("bad: %#v", err) 1091 } 1092 1093 if len(attributes) != 3 { 1094 t.Fatalf("expected number of attributes to be 3, but got %d", len(attributes)) 1095 } 1096 1097 expected := &elb.PolicyAttribute{ 1098 AttributeName: aws.String("Protocol-TLSv1.2"), 1099 AttributeValue: aws.String("true"), 1100 } 1101 1102 if !reflect.DeepEqual(attributes[2], expected) { 1103 t.Fatalf( 1104 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 1105 attributes[2], 1106 expected) 1107 } 1108 } 1109 1110 func TestExpandPolicyAttributes_invalid(t *testing.T) { 1111 expanded := []interface{}{ 1112 map[string]interface{}{ 1113 "name": "Protocol-TLSv1.2", 1114 "value": "true", 1115 }, 1116 } 1117 attributes, err := expandPolicyAttributes(expanded) 1118 if err != nil { 1119 t.Fatalf("bad: %#v", err) 1120 } 1121 1122 expected := &elb.PolicyAttribute{ 1123 AttributeName: aws.String("Protocol-TLSv1.2"), 1124 AttributeValue: aws.String("false"), 1125 } 1126 1127 if reflect.DeepEqual(attributes[0], expected) { 1128 t.Fatalf( 1129 "Got:\n\n%#v\n\nExpected:\n\n%#v\n", 1130 attributes[0], 1131 expected) 1132 } 1133 } 1134 1135 func TestExpandPolicyAttributes_empty(t *testing.T) { 1136 var expanded []interface{} 1137 1138 attributes, err := expandPolicyAttributes(expanded) 1139 if err != nil { 1140 t.Fatalf("bad: %#v", err) 1141 } 1142 1143 if len(attributes) != 0 { 1144 t.Fatalf("expected number of attributes to be 0, but got %d", len(attributes)) 1145 } 1146 } 1147 1148 func TestFlattenPolicyAttributes(t *testing.T) { 1149 cases := []struct { 1150 Input []*elb.PolicyAttributeDescription 1151 Output []interface{} 1152 }{ 1153 { 1154 Input: []*elb.PolicyAttributeDescription{ 1155 &elb.PolicyAttributeDescription{ 1156 AttributeName: aws.String("Protocol-TLSv1.2"), 1157 AttributeValue: aws.String("true"), 1158 }, 1159 }, 1160 Output: []interface{}{ 1161 map[string]string{ 1162 "name": "Protocol-TLSv1.2", 1163 "value": "true", 1164 }, 1165 }, 1166 }, 1167 } 1168 1169 for _, tc := range cases { 1170 output := flattenPolicyAttributes(tc.Input) 1171 if !reflect.DeepEqual(output, tc.Output) { 1172 t.Fatalf("Got:\n\n%#v\n\nExpected:\n\n%#v", output, tc.Output) 1173 } 1174 } 1175 } 1176 1177 func TestNormalizeJsonString(t *testing.T) { 1178 var err error 1179 var actual string 1180 1181 // Well formatted and valid. 1182 validJson := `{ 1183 "abc": { 1184 "def": 123, 1185 "xyz": [ 1186 { 1187 "a": "ホリネズミ" 1188 }, 1189 { 1190 "b": "1\\n2" 1191 } 1192 ] 1193 } 1194 }` 1195 expected := `{"abc":{"def":123,"xyz":[{"a":"ホリネズミ"},{"b":"1\\n2"}]}}` 1196 1197 actual, err = normalizeJsonString(validJson) 1198 if err != nil { 1199 t.Fatalf("Expected not to throw an error while parsing JSON, but got: %s", err) 1200 } 1201 1202 if actual != expected { 1203 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, expected) 1204 } 1205 1206 // Well formatted but not valid, 1207 // missing closing squre bracket. 1208 invalidJson := `{ 1209 "abc": { 1210 "def": 123, 1211 "xyz": [ 1212 { 1213 "a": "1" 1214 } 1215 } 1216 } 1217 }` 1218 actual, err = normalizeJsonString(invalidJson) 1219 if err == nil { 1220 t.Fatalf("Expected to throw an error while parsing JSON, but got: %s", err) 1221 } 1222 1223 // We expect the invalid JSON to be shown back to us again. 1224 if actual != invalidJson { 1225 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", expected, invalidJson) 1226 } 1227 } 1228 1229 func TestCheckYamlString(t *testing.T) { 1230 var err error 1231 var actual string 1232 1233 validYaml := `--- 1234 abc: 1235 def: 123 1236 xyz: 1237 - 1238 a: "ホリネズミ" 1239 b: "1" 1240 ` 1241 1242 actual, err = checkYamlString(validYaml) 1243 if err != nil { 1244 t.Fatalf("Expected not to throw an error while parsing YAML, but got: %s", err) 1245 } 1246 1247 // We expect the same YAML string back 1248 if actual != validYaml { 1249 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, validYaml) 1250 } 1251 1252 invalidYaml := `abc: [` 1253 1254 actual, err = checkYamlString(invalidYaml) 1255 if err == nil { 1256 t.Fatalf("Expected to throw an error while parsing YAML, but got: %s", err) 1257 } 1258 1259 // We expect the invalid YAML to be shown back to us again. 1260 if actual != invalidYaml { 1261 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, invalidYaml) 1262 } 1263 } 1264 1265 func TestNormalizeCloudFormationTemplate(t *testing.T) { 1266 var err error 1267 var actual string 1268 1269 validNormalizedJson := `{"abc":"1"}` 1270 actual, err = normalizeCloudFormationTemplate(validNormalizedJson) 1271 if err != nil { 1272 t.Fatalf("Expected not to throw an error while parsing template, but got: %s", err) 1273 } 1274 if actual != validNormalizedJson { 1275 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, validNormalizedJson) 1276 } 1277 1278 validNormalizedYaml := `abc: 1 1279 ` 1280 actual, err = normalizeCloudFormationTemplate(validNormalizedYaml) 1281 if err != nil { 1282 t.Fatalf("Expected not to throw an error while parsing template, but got: %s", err) 1283 } 1284 if actual != validNormalizedYaml { 1285 t.Fatalf("Got:\n\n%s\n\nExpected:\n\n%s\n", actual, validNormalizedYaml) 1286 } 1287 }