github.com/pbthorste/terraform@v0.8.6-0.20170127005045-deb56bd93da2/builtin/providers/aws/validators_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/aws/aws-sdk-go/service/s3" 9 ) 10 11 func TestValidateEcrRepositoryName(t *testing.T) { 12 validNames := []string{ 13 "nginx-web-app", 14 "project-a/nginx-web-app", 15 "domain.ltd/nginx-web-app", 16 "3chosome-thing.com/01different-pattern", 17 "0123456789/999999999", 18 "double/forward/slash", 19 "000000000000000", 20 } 21 for _, v := range validNames { 22 _, errors := validateEcrRepositoryName(v, "name") 23 if len(errors) != 0 { 24 t.Fatalf("%q should be a valid ECR repository name: %q", v, errors) 25 } 26 } 27 28 invalidNames := []string{ 29 // length > 256 30 "3cho_some-thing.com/01different.-_pattern01different.-_pattern01diff" + 31 "erent.-_pattern01different.-_pattern01different.-_pattern01different" + 32 ".-_pattern01different.-_pattern01different.-_pattern01different.-_pa" + 33 "ttern01different.-_pattern01different.-_pattern234567", 34 // length < 2 35 "i", 36 "special@character", 37 "different+special=character", 38 "double//slash", 39 "double..dot", 40 "/slash-at-the-beginning", 41 "slash-at-the-end/", 42 } 43 for _, v := range invalidNames { 44 _, errors := validateEcrRepositoryName(v, "name") 45 if len(errors) == 0 { 46 t.Fatalf("%q should be an invalid ECR repository name", v) 47 } 48 } 49 } 50 51 func TestValidateCloudWatchEventRuleName(t *testing.T) { 52 validNames := []string{ 53 "HelloWorl_d", 54 "hello-world", 55 "hello.World0125", 56 } 57 for _, v := range validNames { 58 _, errors := validateCloudWatchEventRuleName(v, "name") 59 if len(errors) != 0 { 60 t.Fatalf("%q should be a valid CW event rule name: %q", v, errors) 61 } 62 } 63 64 invalidNames := []string{ 65 "special@character", 66 "slash/in-the-middle", 67 // Length > 64 68 "TooLooooooooooooooooooooooooooooooooooooooooooooooooooooooongName", 69 } 70 for _, v := range invalidNames { 71 _, errors := validateCloudWatchEventRuleName(v, "name") 72 if len(errors) == 0 { 73 t.Fatalf("%q should be an invalid CW event rule name", v) 74 } 75 } 76 } 77 78 func TestValidateLambdaFunctionName(t *testing.T) { 79 validNames := []string{ 80 "arn:aws:lambda:us-west-2:123456789012:function:ThumbNail", 81 "arn:aws-us-gov:lambda:us-west-2:123456789012:function:ThumbNail", 82 "FunctionName", 83 "function-name", 84 } 85 for _, v := range validNames { 86 _, errors := validateLambdaFunctionName(v, "name") 87 if len(errors) != 0 { 88 t.Fatalf("%q should be a valid Lambda function name: %q", v, errors) 89 } 90 } 91 92 invalidNames := []string{ 93 "/FunctionNameWithSlash", 94 "function.name.with.dots", 95 // length > 140 96 "arn:aws:lambda:us-west-2:123456789012:function:TooLoooooo" + 97 "ooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + 98 "ooooooooooooooooongFunctionName", 99 } 100 for _, v := range invalidNames { 101 _, errors := validateLambdaFunctionName(v, "name") 102 if len(errors) == 0 { 103 t.Fatalf("%q should be an invalid Lambda function name", v) 104 } 105 } 106 } 107 108 func TestValidateLambdaQualifier(t *testing.T) { 109 validNames := []string{ 110 "123", 111 "prod", 112 "PROD", 113 "MyTestEnv", 114 "contains-dashes", 115 "contains_underscores", 116 "$LATEST", 117 } 118 for _, v := range validNames { 119 _, errors := validateLambdaQualifier(v, "name") 120 if len(errors) != 0 { 121 t.Fatalf("%q should be a valid Lambda function qualifier: %q", v, errors) 122 } 123 } 124 125 invalidNames := []string{ 126 // No ARNs allowed 127 "arn:aws:lambda:us-west-2:123456789012:function:prod", 128 // length > 128 129 "TooLooooooooooooooooooooooooooooooooooooooooooooooooooo" + 130 "ooooooooooooooooooooooooooooooooooooooooooooooooooo" + 131 "oooooooooooongQualifier", 132 } 133 for _, v := range invalidNames { 134 _, errors := validateLambdaQualifier(v, "name") 135 if len(errors) == 0 { 136 t.Fatalf("%q should be an invalid Lambda function qualifier", v) 137 } 138 } 139 } 140 141 func TestValidateLambdaPermissionAction(t *testing.T) { 142 validNames := []string{ 143 "lambda:*", 144 "lambda:InvokeFunction", 145 "*", 146 } 147 for _, v := range validNames { 148 _, errors := validateLambdaPermissionAction(v, "action") 149 if len(errors) != 0 { 150 t.Fatalf("%q should be a valid Lambda permission action: %q", v, errors) 151 } 152 } 153 154 invalidNames := []string{ 155 "yada", 156 "lambda:123", 157 "*:*", 158 "lambda:Invoke*", 159 } 160 for _, v := range invalidNames { 161 _, errors := validateLambdaPermissionAction(v, "action") 162 if len(errors) == 0 { 163 t.Fatalf("%q should be an invalid Lambda permission action", v) 164 } 165 } 166 } 167 168 func TestValidateAwsAccountId(t *testing.T) { 169 validNames := []string{ 170 "123456789012", 171 "999999999999", 172 } 173 for _, v := range validNames { 174 _, errors := validateAwsAccountId(v, "account_id") 175 if len(errors) != 0 { 176 t.Fatalf("%q should be a valid AWS Account ID: %q", v, errors) 177 } 178 } 179 180 invalidNames := []string{ 181 "12345678901", // too short 182 "1234567890123", // too long 183 "invalid", 184 "x123456789012", 185 } 186 for _, v := range invalidNames { 187 _, errors := validateAwsAccountId(v, "account_id") 188 if len(errors) == 0 { 189 t.Fatalf("%q should be an invalid AWS Account ID", v) 190 } 191 } 192 } 193 194 func TestValidateArn(t *testing.T) { 195 v := "" 196 _, errors := validateArn(v, "arn") 197 if len(errors) != 0 { 198 t.Fatalf("%q should not be validated as an ARN: %q", v, errors) 199 } 200 201 validNames := []string{ 202 "arn:aws:elasticbeanstalk:us-east-1:123456789012:environment/My App/MyEnvironment", // Beanstalk 203 "arn:aws:iam::123456789012:user/David", // IAM User 204 "arn:aws:rds:eu-west-1:123456789012:db:mysql-db", // RDS 205 "arn:aws:s3:::my_corporate_bucket/exampleobject.png", // S3 object 206 "arn:aws:events:us-east-1:319201112229:rule/rule_name", // CloudWatch Rule 207 "arn:aws:lambda:eu-west-1:319201112229:function:myCustomFunction", // Lambda function 208 "arn:aws:lambda:eu-west-1:319201112229:function:myCustomFunction:Qualifier", // Lambda func qualifier 209 "arn:aws-us-gov:s3:::corp_bucket/object.png", // GovCloud ARN 210 } 211 for _, v := range validNames { 212 _, errors := validateArn(v, "arn") 213 if len(errors) != 0 { 214 t.Fatalf("%q should be a valid ARN: %q", v, errors) 215 } 216 } 217 218 invalidNames := []string{ 219 "arn", 220 "123456789012", 221 "arn:aws", 222 "arn:aws:logs", 223 "arn:aws:logs:region:*:*", 224 } 225 for _, v := range invalidNames { 226 _, errors := validateArn(v, "arn") 227 if len(errors) == 0 { 228 t.Fatalf("%q should be an invalid ARN", v) 229 } 230 } 231 } 232 233 func TestValidatePolicyStatementId(t *testing.T) { 234 validNames := []string{ 235 "YadaHereAndThere", 236 "Valid-5tatement_Id", 237 "1234", 238 } 239 for _, v := range validNames { 240 _, errors := validatePolicyStatementId(v, "statement_id") 241 if len(errors) != 0 { 242 t.Fatalf("%q should be a valid Statement ID: %q", v, errors) 243 } 244 } 245 246 invalidNames := []string{ 247 "Invalid/StatementId/with/slashes", 248 "InvalidStatementId.with.dots", 249 // length > 100 250 "TooooLoooooooooooooooooooooooooooooooooooooooooooo" + 251 "ooooooooooooooooooooooooooooooooooooooooStatementId", 252 } 253 for _, v := range invalidNames { 254 _, errors := validatePolicyStatementId(v, "statement_id") 255 if len(errors) == 0 { 256 t.Fatalf("%q should be an invalid Statement ID", v) 257 } 258 } 259 } 260 261 func TestValidateCIDRNetworkAddress(t *testing.T) { 262 cases := []struct { 263 CIDR string 264 ExpectedErrSubstr string 265 }{ 266 {"notacidr", `must contain a valid CIDR`}, 267 {"10.0.1.0/16", `must contain a valid network CIDR`}, 268 {"10.0.1.0/24", ``}, 269 } 270 271 for i, tc := range cases { 272 _, errs := validateCIDRNetworkAddress(tc.CIDR, "foo") 273 if tc.ExpectedErrSubstr == "" { 274 if len(errs) != 0 { 275 t.Fatalf("%d/%d: Expected no error, got errs: %#v", 276 i+1, len(cases), errs) 277 } 278 } else { 279 if len(errs) != 1 { 280 t.Fatalf("%d/%d: Expected 1 err containing %q, got %d errs", 281 i+1, len(cases), tc.ExpectedErrSubstr, len(errs)) 282 } 283 if !strings.Contains(errs[0].Error(), tc.ExpectedErrSubstr) { 284 t.Fatalf("%d/%d: Expected err: %q, to include %q", 285 i+1, len(cases), errs[0], tc.ExpectedErrSubstr) 286 } 287 } 288 } 289 } 290 291 func TestValidateHTTPMethod(t *testing.T) { 292 type testCases struct { 293 Value string 294 ErrCount int 295 } 296 297 invalidCases := []testCases{ 298 { 299 Value: "incorrect", 300 ErrCount: 1, 301 }, 302 { 303 Value: "delete", 304 ErrCount: 1, 305 }, 306 } 307 308 for _, tc := range invalidCases { 309 _, errors := validateHTTPMethod(tc.Value, "http_method") 310 if len(errors) != tc.ErrCount { 311 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 312 } 313 } 314 315 validCases := []testCases{ 316 { 317 Value: "ANY", 318 ErrCount: 0, 319 }, 320 { 321 Value: "DELETE", 322 ErrCount: 0, 323 }, 324 { 325 Value: "OPTIONS", 326 ErrCount: 0, 327 }, 328 } 329 330 for _, tc := range validCases { 331 _, errors := validateHTTPMethod(tc.Value, "http_method") 332 if len(errors) != tc.ErrCount { 333 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 334 } 335 } 336 } 337 338 func TestValidateLogMetricFilterName(t *testing.T) { 339 validNames := []string{ 340 "YadaHereAndThere", 341 "Valid-5Metric_Name", 342 "This . is also %% valid@!)+(", 343 "1234", 344 strings.Repeat("W", 512), 345 } 346 for _, v := range validNames { 347 _, errors := validateLogMetricFilterName(v, "name") 348 if len(errors) != 0 { 349 t.Fatalf("%q should be a valid Log Metric Filter Name: %q", v, errors) 350 } 351 } 352 353 invalidNames := []string{ 354 "Here is a name with: colon", 355 "and here is another * invalid name", 356 "*", 357 // length > 512 358 strings.Repeat("W", 513), 359 } 360 for _, v := range invalidNames { 361 _, errors := validateLogMetricFilterName(v, "name") 362 if len(errors) == 0 { 363 t.Fatalf("%q should be an invalid Log Metric Filter Name", v) 364 } 365 } 366 } 367 368 func TestValidateLogMetricTransformationName(t *testing.T) { 369 validNames := []string{ 370 "YadaHereAndThere", 371 "Valid-5Metric_Name", 372 "This . is also %% valid@!)+(", 373 "1234", 374 "", 375 strings.Repeat("W", 255), 376 } 377 for _, v := range validNames { 378 _, errors := validateLogMetricFilterTransformationName(v, "name") 379 if len(errors) != 0 { 380 t.Fatalf("%q should be a valid Log Metric Filter Transformation Name: %q", v, errors) 381 } 382 } 383 384 invalidNames := []string{ 385 "Here is a name with: colon", 386 "and here is another * invalid name", 387 "also $ invalid", 388 "*", 389 // length > 255 390 strings.Repeat("W", 256), 391 } 392 for _, v := range invalidNames { 393 _, errors := validateLogMetricFilterTransformationName(v, "name") 394 if len(errors) == 0 { 395 t.Fatalf("%q should be an invalid Log Metric Filter Transformation Name", v) 396 } 397 } 398 } 399 400 func TestValidateLogGroupName(t *testing.T) { 401 validNames := []string{ 402 "ValidLogGroupName", 403 "ValidLogGroup.Name", 404 "valid/Log-group", 405 "1234", 406 "YadaValid#0123", 407 "Also_valid-name", 408 strings.Repeat("W", 512), 409 } 410 for _, v := range validNames { 411 _, errors := validateLogGroupName(v, "name") 412 if len(errors) != 0 { 413 t.Fatalf("%q should be a valid Log Metric Filter Transformation Name: %q", v, errors) 414 } 415 } 416 417 invalidNames := []string{ 418 "Here is a name with: colon", 419 "and here is another * invalid name", 420 "also $ invalid", 421 "This . is also %% invalid@!)+(", 422 "*", 423 "", 424 // length > 512 425 strings.Repeat("W", 513), 426 } 427 for _, v := range invalidNames { 428 _, errors := validateLogGroupName(v, "name") 429 if len(errors) == 0 { 430 t.Fatalf("%q should be an invalid Log Metric Filter Transformation Name", v) 431 } 432 } 433 } 434 435 func TestValidateS3BucketLifecycleTimestamp(t *testing.T) { 436 validDates := []string{ 437 "2016-01-01", 438 "2006-01-02", 439 } 440 441 for _, v := range validDates { 442 _, errors := validateS3BucketLifecycleTimestamp(v, "date") 443 if len(errors) != 0 { 444 t.Fatalf("%q should be valid date: %q", v, errors) 445 } 446 } 447 448 invalidDates := []string{ 449 "Jan 01 2016", 450 "20160101", 451 } 452 453 for _, v := range invalidDates { 454 _, errors := validateS3BucketLifecycleTimestamp(v, "date") 455 if len(errors) == 0 { 456 t.Fatalf("%q should be invalid date", v) 457 } 458 } 459 } 460 461 func TestValidateS3BucketLifecycleStorageClass(t *testing.T) { 462 validStorageClass := []string{ 463 "STANDARD_IA", 464 "GLACIER", 465 } 466 467 for _, v := range validStorageClass { 468 _, errors := validateS3BucketLifecycleStorageClass(v, "storage_class") 469 if len(errors) != 0 { 470 t.Fatalf("%q should be valid storage class: %q", v, errors) 471 } 472 } 473 474 invalidStorageClass := []string{ 475 "STANDARD", 476 "1234", 477 } 478 for _, v := range invalidStorageClass { 479 _, errors := validateS3BucketLifecycleStorageClass(v, "storage_class") 480 if len(errors) == 0 { 481 t.Fatalf("%q should be invalid storage class", v) 482 } 483 } 484 } 485 486 func TestValidateS3BucketReplicationRuleId(t *testing.T) { 487 validId := []string{ 488 "YadaHereAndThere", 489 "Valid-5Rule_ID", 490 "This . is also %% valid@!)+*(:ID", 491 "1234", 492 strings.Repeat("W", 255), 493 } 494 for _, v := range validId { 495 _, errors := validateS3BucketReplicationRuleId(v, "id") 496 if len(errors) != 0 { 497 t.Fatalf("%q should be a valid lifecycle rule id: %q", v, errors) 498 } 499 } 500 501 invalidId := []string{ 502 // length > 255 503 strings.Repeat("W", 256), 504 } 505 for _, v := range invalidId { 506 _, errors := validateS3BucketReplicationRuleId(v, "id") 507 if len(errors) == 0 { 508 t.Fatalf("%q should be an invalid replication configuration rule id", v) 509 } 510 } 511 } 512 513 func TestValidateS3BucketReplicationRulePrefix(t *testing.T) { 514 validId := []string{ 515 "YadaHereAndThere", 516 "Valid-5Rule_ID", 517 "This . is also %% valid@!)+*(:ID", 518 "1234", 519 strings.Repeat("W", 1024), 520 } 521 for _, v := range validId { 522 _, errors := validateS3BucketReplicationRulePrefix(v, "id") 523 if len(errors) != 0 { 524 t.Fatalf("%q should be a valid lifecycle rule id: %q", v, errors) 525 } 526 } 527 528 invalidId := []string{ 529 // length > 1024 530 strings.Repeat("W", 1025), 531 } 532 for _, v := range invalidId { 533 _, errors := validateS3BucketReplicationRulePrefix(v, "id") 534 if len(errors) == 0 { 535 t.Fatalf("%q should be an invalid replication configuration rule id", v) 536 } 537 } 538 } 539 540 func TestValidateS3BucketReplicationDestinationStorageClass(t *testing.T) { 541 validStorageClass := []string{ 542 s3.StorageClassStandard, 543 s3.StorageClassStandardIa, 544 s3.StorageClassReducedRedundancy, 545 } 546 547 for _, v := range validStorageClass { 548 _, errors := validateS3BucketReplicationDestinationStorageClass(v, "storage_class") 549 if len(errors) != 0 { 550 t.Fatalf("%q should be valid storage class: %q", v, errors) 551 } 552 } 553 554 invalidStorageClass := []string{ 555 "FOO", 556 "1234", 557 } 558 for _, v := range invalidStorageClass { 559 _, errors := validateS3BucketReplicationDestinationStorageClass(v, "storage_class") 560 if len(errors) == 0 { 561 t.Fatalf("%q should be invalid storage class", v) 562 } 563 } 564 } 565 566 func TestValidateS3BucketReplicationRuleStatus(t *testing.T) { 567 validRuleStatuses := []string{ 568 s3.ReplicationRuleStatusEnabled, 569 s3.ReplicationRuleStatusDisabled, 570 } 571 572 for _, v := range validRuleStatuses { 573 _, errors := validateS3BucketReplicationRuleStatus(v, "status") 574 if len(errors) != 0 { 575 t.Fatalf("%q should be valid rule status: %q", v, errors) 576 } 577 } 578 579 invalidRuleStatuses := []string{ 580 "FOO", 581 "1234", 582 } 583 for _, v := range invalidRuleStatuses { 584 _, errors := validateS3BucketReplicationRuleStatus(v, "status") 585 if len(errors) == 0 { 586 t.Fatalf("%q should be invalid rule status", v) 587 } 588 } 589 } 590 591 func TestValidateS3BucketLifecycleRuleId(t *testing.T) { 592 validId := []string{ 593 "YadaHereAndThere", 594 "Valid-5Rule_ID", 595 "This . is also %% valid@!)+*(:ID", 596 "1234", 597 strings.Repeat("W", 255), 598 } 599 for _, v := range validId { 600 _, errors := validateS3BucketLifecycleRuleId(v, "id") 601 if len(errors) != 0 { 602 t.Fatalf("%q should be a valid lifecycle rule id: %q", v, errors) 603 } 604 } 605 606 invalidId := []string{ 607 // length > 255 608 strings.Repeat("W", 256), 609 } 610 for _, v := range invalidId { 611 _, errors := validateS3BucketLifecycleRuleId(v, "id") 612 if len(errors) == 0 { 613 t.Fatalf("%q should be an invalid lifecycle rule id", v) 614 } 615 } 616 } 617 618 func TestValidateIntegerInRange(t *testing.T) { 619 validIntegers := []int{-259, 0, 1, 5, 999} 620 min := -259 621 max := 999 622 for _, v := range validIntegers { 623 _, errors := validateIntegerInRange(min, max)(v, "name") 624 if len(errors) != 0 { 625 t.Fatalf("%q should be an integer in range (%d, %d): %q", v, min, max, errors) 626 } 627 } 628 629 invalidIntegers := []int{-260, -99999, 1000, 25678} 630 for _, v := range invalidIntegers { 631 _, errors := validateIntegerInRange(min, max)(v, "name") 632 if len(errors) == 0 { 633 t.Fatalf("%q should be an integer outside range (%d, %d)", v, min, max) 634 } 635 } 636 } 637 638 func TestResourceAWSElastiCacheClusterIdValidation(t *testing.T) { 639 cases := []struct { 640 Value string 641 ErrCount int 642 }{ 643 { 644 Value: "tEsting", 645 ErrCount: 1, 646 }, 647 { 648 Value: "t.sting", 649 ErrCount: 1, 650 }, 651 { 652 Value: "t--sting", 653 ErrCount: 1, 654 }, 655 { 656 Value: "1testing", 657 ErrCount: 1, 658 }, 659 { 660 Value: "testing-", 661 ErrCount: 1, 662 }, 663 { 664 Value: randomString(65), 665 ErrCount: 1, 666 }, 667 } 668 669 for _, tc := range cases { 670 _, errors := validateElastiCacheClusterId(tc.Value, "aws_elasticache_cluster_cluster_id") 671 672 if len(errors) != tc.ErrCount { 673 t.Fatalf("Expected the ElastiCache Cluster cluster_id to trigger a validation error") 674 } 675 } 676 } 677 678 func TestValidateDbEventSubscriptionName(t *testing.T) { 679 validNames := []string{ 680 "valid-name", 681 "valid02-name", 682 "Valid-Name1", 683 } 684 for _, v := range validNames { 685 _, errors := validateDbEventSubscriptionName(v, "name") 686 if len(errors) != 0 { 687 t.Fatalf("%q should be a valid RDS Event Subscription Name: %q", v, errors) 688 } 689 } 690 691 invalidNames := []string{ 692 "Here is a name with: colon", 693 "and here is another * invalid name", 694 "also $ invalid", 695 "This . is also %% invalid@!)+(", 696 "*", 697 "", 698 " ", 699 "_", 700 // length > 255 701 strings.Repeat("W", 256), 702 } 703 for _, v := range invalidNames { 704 _, errors := validateDbEventSubscriptionName(v, "name") 705 if len(errors) == 0 { 706 t.Fatalf("%q should be an invalid RDS Event Subscription Name", v) 707 } 708 } 709 } 710 711 func TestValidateJsonString(t *testing.T) { 712 type testCases struct { 713 Value string 714 ErrCount int 715 } 716 717 invalidCases := []testCases{ 718 { 719 Value: `{0:"1"}`, 720 ErrCount: 1, 721 }, 722 { 723 Value: `{'abc':1}`, 724 ErrCount: 1, 725 }, 726 { 727 Value: `{"def":}`, 728 ErrCount: 1, 729 }, 730 { 731 Value: `{"xyz":[}}`, 732 ErrCount: 1, 733 }, 734 } 735 736 for _, tc := range invalidCases { 737 _, errors := validateJsonString(tc.Value, "json") 738 if len(errors) != tc.ErrCount { 739 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 740 } 741 } 742 743 validCases := []testCases{ 744 { 745 Value: ``, 746 ErrCount: 0, 747 }, 748 { 749 Value: `{}`, 750 ErrCount: 0, 751 }, 752 { 753 Value: `{"abc":["1","2"]}`, 754 ErrCount: 0, 755 }, 756 } 757 758 for _, tc := range validCases { 759 _, errors := validateJsonString(tc.Value, "json") 760 if len(errors) != tc.ErrCount { 761 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 762 } 763 } 764 } 765 766 func TestValidateCloudFormationTemplate(t *testing.T) { 767 type testCases struct { 768 Value string 769 ErrCount int 770 } 771 772 invalidCases := []testCases{ 773 { 774 Value: `{"abc":"`, 775 ErrCount: 1, 776 }, 777 { 778 Value: "abc: [", 779 ErrCount: 1, 780 }, 781 } 782 783 for _, tc := range invalidCases { 784 _, errors := validateCloudFormationTemplate(tc.Value, "template") 785 if len(errors) != tc.ErrCount { 786 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 787 } 788 } 789 790 validCases := []testCases{ 791 { 792 Value: `{"abc":"1"}`, 793 ErrCount: 0, 794 }, 795 { 796 Value: `abc: 1`, 797 ErrCount: 0, 798 }, 799 } 800 801 for _, tc := range validCases { 802 _, errors := validateCloudFormationTemplate(tc.Value, "template") 803 if len(errors) != tc.ErrCount { 804 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 805 } 806 } 807 } 808 809 func TestValidateApiGatewayIntegrationType(t *testing.T) { 810 type testCases struct { 811 Value string 812 ErrCount int 813 } 814 815 invalidCases := []testCases{ 816 { 817 Value: "incorrect", 818 ErrCount: 1, 819 }, 820 { 821 Value: "aws_proxy", 822 ErrCount: 1, 823 }, 824 } 825 826 for _, tc := range invalidCases { 827 _, errors := validateApiGatewayIntegrationType(tc.Value, "types") 828 if len(errors) != tc.ErrCount { 829 t.Fatalf("Expected %q to trigger a validation error.", tc.Value) 830 } 831 } 832 833 validCases := []testCases{ 834 { 835 Value: "MOCK", 836 ErrCount: 0, 837 }, 838 { 839 Value: "AWS_PROXY", 840 ErrCount: 0, 841 }, 842 } 843 844 for _, tc := range validCases { 845 _, errors := validateApiGatewayIntegrationType(tc.Value, "types") 846 if len(errors) != tc.ErrCount { 847 t.Fatalf("Expected %q not to trigger a validation error.", tc.Value) 848 } 849 } 850 } 851 852 func TestValidateSQSQueueName(t *testing.T) { 853 validNames := []string{ 854 "valid-name", 855 "valid02-name", 856 "Valid-Name1", 857 "_", 858 "-", 859 strings.Repeat("W", 80), 860 } 861 for _, v := range validNames { 862 if errors := validateSQSQueueName(v, "name"); len(errors) > 0 { 863 t.Fatalf("%q should be a valid SQS queue Name", v) 864 } 865 } 866 867 invalidNames := []string{ 868 "Here is a name with: colon", 869 "another * invalid name", 870 "also $ invalid", 871 "This . is also %% invalid@!)+(", 872 "*", 873 "", 874 " ", 875 ".", 876 strings.Repeat("W", 81), // length > 80 877 } 878 for _, v := range invalidNames { 879 if errors := validateSQSQueueName(v, "name"); len(errors) == 0 { 880 t.Fatalf("%q should be an invalid SQS queue Name", v) 881 } 882 } 883 } 884 885 func TestValidateSQSFifoQueueName(t *testing.T) { 886 validNames := []string{ 887 "valid-name.fifo", 888 "valid02-name.fifo", 889 "Valid-Name1.fifo", 890 "_.fifo", 891 "a.fifo", 892 "A.fifo", 893 "9.fifo", 894 "-.fifo", 895 fmt.Sprintf("%s.fifo", strings.Repeat("W", 75)), 896 } 897 for _, v := range validNames { 898 if errors := validateSQSFifoQueueName(v, "name"); len(errors) > 0 { 899 t.Fatalf("%q should be a valid SQS FIFO queue Name: %v", v, errors) 900 } 901 } 902 903 invalidNames := []string{ 904 "Here is a name with: colon", 905 "another * invalid name", 906 "also $ invalid", 907 "This . is also %% invalid@!)+(", 908 ".fifo", 909 "*", 910 "", 911 " ", 912 ".", 913 strings.Repeat("W", 81), // length > 80 914 } 915 for _, v := range invalidNames { 916 if errors := validateSQSFifoQueueName(v, "name"); len(errors) == 0 { 917 t.Fatalf("%q should be an invalid SQS FIFO queue Name: %v", v, errors) 918 } 919 } 920 } 921 922 func TestValidateSNSSubscriptionProtocol(t *testing.T) { 923 validProtocols := []string{ 924 "lambda", 925 "sqs", 926 "sqs", 927 "application", 928 "http", 929 "https", 930 } 931 for _, v := range validProtocols { 932 if _, errors := validateSNSSubscriptionProtocol(v, "protocol"); len(errors) > 0 { 933 t.Fatalf("%q should be a valid SNS Subscription protocol: %v", v, errors) 934 } 935 } 936 937 invalidProtocols := []string{ 938 "Email", 939 "email", 940 "Email-JSON", 941 "email-json", 942 "SMS", 943 "sms", 944 } 945 for _, v := range invalidProtocols { 946 if _, errors := validateSNSSubscriptionProtocol(v, "protocol"); len(errors) == 0 { 947 t.Fatalf("%q should be an invalid SNS Subscription protocol: %v", v, errors) 948 } 949 } 950 } 951 952 func TestValidateSecurityRuleType(t *testing.T) { 953 validTypes := []string{ 954 "ingress", 955 "egress", 956 } 957 for _, v := range validTypes { 958 if _, errors := validateSecurityRuleType(v, "type"); len(errors) > 0 { 959 t.Fatalf("%q should be a valid Security Group Rule type: %v", v, errors) 960 } 961 } 962 963 invalidTypes := []string{ 964 "foo", 965 "ingresss", 966 } 967 for _, v := range invalidTypes { 968 if _, errors := validateSecurityRuleType(v, "type"); len(errors) == 0 { 969 t.Fatalf("%q should be an invalid Security Group Rule type: %v", v, errors) 970 } 971 } 972 } 973 974 func TestValidateOnceAWeekWindowFormat(t *testing.T) { 975 cases := []struct { 976 Value string 977 ErrCount int 978 }{ 979 { 980 // once a day window format 981 Value: "04:00-05:00", 982 ErrCount: 1, 983 }, 984 { 985 // invalid day of week 986 Value: "san:04:00-san:05:00", 987 ErrCount: 1, 988 }, 989 { 990 // invalid hour 991 Value: "sun:24:00-san:25:00", 992 ErrCount: 1, 993 }, 994 { 995 // invalid min 996 Value: "sun:04:00-sun:04:60", 997 ErrCount: 1, 998 }, 999 { 1000 // valid format 1001 Value: "sun:04:00-sun:05:00", 1002 ErrCount: 0, 1003 }, 1004 { 1005 // "Sun" can also be used 1006 Value: "Sun:04:00-Sun:05:00", 1007 ErrCount: 0, 1008 }, 1009 } 1010 1011 for _, tc := range cases { 1012 _, errors := validateOnceAWeekWindowFormat(tc.Value, "maintenance_window") 1013 1014 if len(errors) != tc.ErrCount { 1015 t.Fatalf("Expected %d validation errors, But got %d errors for \"%s\"", tc.ErrCount, len(errors), tc.Value) 1016 } 1017 } 1018 } 1019 1020 func TestValidateOnceADayWindowFormat(t *testing.T) { 1021 cases := []struct { 1022 Value string 1023 ErrCount int 1024 }{ 1025 { 1026 // once a week window format 1027 Value: "sun:04:00-sun:05:00", 1028 ErrCount: 1, 1029 }, 1030 { 1031 // invalid hour 1032 Value: "24:00-25:00", 1033 ErrCount: 1, 1034 }, 1035 { 1036 // invalid min 1037 Value: "04:00-04:60", 1038 ErrCount: 1, 1039 }, 1040 { 1041 // valid format 1042 Value: "04:00-05:00", 1043 ErrCount: 0, 1044 }, 1045 } 1046 1047 for _, tc := range cases { 1048 _, errors := validateOnceADayWindowFormat(tc.Value, "backup_window") 1049 1050 if len(errors) != tc.ErrCount { 1051 t.Fatalf("Expected %d validation errors, But got %d errors for \"%s\"", tc.ErrCount, len(errors), tc.Value) 1052 } 1053 } 1054 } 1055 1056 func TestValidateRoute53RecordType(t *testing.T) { 1057 validTypes := []string{ 1058 "AAAA", 1059 "SOA", 1060 "A", 1061 "TXT", 1062 "CNAME", 1063 "MX", 1064 "NAPTR", 1065 "PTR", 1066 "SPF", 1067 "SRV", 1068 "NS", 1069 } 1070 1071 invalidTypes := []string{ 1072 "a", 1073 "alias", 1074 "SpF", 1075 "Txt", 1076 "AaAA", 1077 } 1078 1079 for _, v := range validTypes { 1080 _, errors := validateRoute53RecordType(v, "route53_record") 1081 if len(errors) != 0 { 1082 t.Fatalf("%q should be a valid Route53 record type: %v", v, errors) 1083 } 1084 } 1085 1086 for _, v := range invalidTypes { 1087 _, errors := validateRoute53RecordType(v, "route53_record") 1088 if len(errors) == 0 { 1089 t.Fatalf("%q should not be a valid Route53 record type", v) 1090 } 1091 } 1092 } 1093 1094 func TestValidateEcsPlacementConstraint(t *testing.T) { 1095 cases := []struct { 1096 constType string 1097 constExpr string 1098 Err bool 1099 }{ 1100 { 1101 constType: "distinctInstance", 1102 constExpr: "", 1103 Err: false, 1104 }, 1105 { 1106 constType: "memberOf", 1107 constExpr: "", 1108 Err: true, 1109 }, 1110 { 1111 constType: "distinctInstance", 1112 constExpr: "expression", 1113 Err: false, 1114 }, 1115 { 1116 constType: "memberOf", 1117 constExpr: "expression", 1118 Err: false, 1119 }, 1120 } 1121 1122 for _, tc := range cases { 1123 if err := validateAwsEcsPlacementConstraint(tc.constType, tc.constExpr); err != nil && !tc.Err { 1124 t.Fatalf("Unexpected validation error for \"%s:%s\": %s", 1125 tc.constType, tc.constExpr, err) 1126 } 1127 1128 } 1129 } 1130 1131 func TestValidateEcsPlacementStrategy(t *testing.T) { 1132 cases := []struct { 1133 stratType string 1134 stratField string 1135 Err bool 1136 }{ 1137 { 1138 stratType: "random", 1139 stratField: "", 1140 Err: false, 1141 }, 1142 { 1143 stratType: "spread", 1144 stratField: "instanceID", 1145 Err: false, 1146 }, 1147 { 1148 stratType: "binpack", 1149 stratField: "cpu", 1150 Err: false, 1151 }, 1152 { 1153 stratType: "binpack", 1154 stratField: "memory", 1155 Err: false, 1156 }, 1157 { 1158 stratType: "binpack", 1159 stratField: "disk", 1160 Err: true, 1161 }, 1162 { 1163 stratType: "fakeType", 1164 stratField: "", 1165 Err: true, 1166 }, 1167 } 1168 1169 for _, tc := range cases { 1170 if err := validateAwsEcsPlacementStrategy(tc.stratType, tc.stratField); err != nil && !tc.Err { 1171 t.Fatalf("Unexpected validation error for \"%s:%s\": %s", 1172 tc.stratType, tc.stratField, err) 1173 } 1174 1175 } 1176 }