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  }