github.com/nginxinc/kubernetes-ingress@v1.12.5/pkg/apis/configuration/validation/transportserver_test.go (about)

     1  package validation
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1"
     7  	"k8s.io/apimachinery/pkg/util/sets"
     8  	"k8s.io/apimachinery/pkg/util/validation/field"
     9  )
    10  
    11  func createTransportServerValidator() *TransportServerValidator {
    12  	return &TransportServerValidator{}
    13  }
    14  
    15  func TestValidateTransportServer(t *testing.T) {
    16  	ts := v1alpha1.TransportServer{
    17  		Spec: v1alpha1.TransportServerSpec{
    18  			Listener: v1alpha1.TransportServerListener{
    19  				Name:     "tcp-listener",
    20  				Protocol: "TCP",
    21  			},
    22  			Upstreams: []v1alpha1.Upstream{
    23  				{
    24  					Name:    "upstream1",
    25  					Service: "test-1",
    26  					Port:    5501,
    27  				},
    28  			},
    29  			Action: &v1alpha1.Action{
    30  				Pass: "upstream1",
    31  			},
    32  		},
    33  	}
    34  
    35  	tsv := createTransportServerValidator()
    36  
    37  	err := tsv.ValidateTransportServer(&ts)
    38  	if err != nil {
    39  		t.Errorf("ValidateTransportServer() returned error %v for valid input", err)
    40  	}
    41  }
    42  
    43  func TestValidateTransportServerFails(t *testing.T) {
    44  	ts := v1alpha1.TransportServer{
    45  		Spec: v1alpha1.TransportServerSpec{
    46  			Listener: v1alpha1.TransportServerListener{
    47  				Name:     "tcp-listener",
    48  				Protocol: "TCP",
    49  			},
    50  			Upstreams: []v1alpha1.Upstream{
    51  				{
    52  					Name:    "upstream1",
    53  					Service: "test-1",
    54  					Port:    5501,
    55  				},
    56  			},
    57  			Action: nil,
    58  		},
    59  	}
    60  
    61  	tsv := createTransportServerValidator()
    62  
    63  	err := tsv.ValidateTransportServer(&ts)
    64  	if err == nil {
    65  		t.Errorf("ValidateTransportServer() returned no error for invalid input")
    66  	}
    67  }
    68  
    69  func TestValidateTransportServerUpstreams(t *testing.T) {
    70  	tests := []struct {
    71  		upstreams             []v1alpha1.Upstream
    72  		expectedUpstreamNames sets.String
    73  		msg                   string
    74  	}{
    75  		{
    76  			upstreams:             []v1alpha1.Upstream{},
    77  			expectedUpstreamNames: sets.String{},
    78  			msg:                   "no upstreams",
    79  		},
    80  		{
    81  			upstreams: []v1alpha1.Upstream{
    82  				{
    83  					Name:    "upstream1",
    84  					Service: "test-1",
    85  					Port:    80,
    86  				},
    87  				{
    88  					Name:    "upstream2",
    89  					Service: "test-2",
    90  					Port:    80,
    91  				},
    92  			},
    93  			expectedUpstreamNames: map[string]sets.Empty{
    94  				"upstream1": {},
    95  				"upstream2": {},
    96  			},
    97  			msg: "2 valid upstreams",
    98  		},
    99  	}
   100  
   101  	for _, test := range tests {
   102  		allErrs, resultUpstreamNames := validateTransportServerUpstreams(test.upstreams, field.NewPath("upstreams"), true)
   103  		if len(allErrs) > 0 {
   104  			t.Errorf("validateTransportServerUpstreams() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   105  		}
   106  		if !resultUpstreamNames.Equal(test.expectedUpstreamNames) {
   107  			t.Errorf("validateTransportServerUpstreams() returned %v expected %v for the case of %s", resultUpstreamNames, test.expectedUpstreamNames, test.msg)
   108  		}
   109  	}
   110  }
   111  
   112  func TestValidateTransportServerUpstreamsFails(t *testing.T) {
   113  	tests := []struct {
   114  		upstreams             []v1alpha1.Upstream
   115  		expectedUpstreamNames sets.String
   116  		msg                   string
   117  	}{
   118  		{
   119  			upstreams: []v1alpha1.Upstream{
   120  				{
   121  					Name:    "@upstream1",
   122  					Service: "test-1",
   123  					Port:    80,
   124  				},
   125  			},
   126  			expectedUpstreamNames: sets.String{},
   127  			msg:                   "invalid upstream name",
   128  		},
   129  		{
   130  			upstreams: []v1alpha1.Upstream{
   131  				{
   132  					Name:    "upstream1",
   133  					Service: "@test-1",
   134  					Port:    80,
   135  				},
   136  			},
   137  			expectedUpstreamNames: map[string]sets.Empty{
   138  				"upstream1": {},
   139  			},
   140  			msg: "invalid service",
   141  		},
   142  		{
   143  			upstreams: []v1alpha1.Upstream{
   144  				{
   145  					Name:    "upstream1",
   146  					Service: "test-1",
   147  					Port:    -80,
   148  				},
   149  			},
   150  			expectedUpstreamNames: map[string]sets.Empty{
   151  				"upstream1": {},
   152  			},
   153  			msg: "invalid port",
   154  		},
   155  		{
   156  			upstreams: []v1alpha1.Upstream{
   157  				{
   158  					Name:    "upstream1",
   159  					Service: "test-1",
   160  					Port:    80,
   161  				},
   162  				{
   163  					Name:    "upstream1",
   164  					Service: "test-2",
   165  					Port:    80,
   166  				},
   167  			},
   168  			expectedUpstreamNames: map[string]sets.Empty{
   169  				"upstream1": {},
   170  			},
   171  			msg: "duplicated upstreams",
   172  		},
   173  	}
   174  
   175  	for _, test := range tests {
   176  		allErrs, resultUpstreamNames := validateTransportServerUpstreams(test.upstreams, field.NewPath("upstreams"), true)
   177  		if len(allErrs) == 0 {
   178  			t.Errorf("validateTransportServerUpstreams() returned no errors for the case of %s", test.msg)
   179  		}
   180  		if !resultUpstreamNames.Equal(test.expectedUpstreamNames) {
   181  			t.Errorf("validateTransportServerUpstreams() returned %v expected %v for the case of %s", resultUpstreamNames, test.expectedUpstreamNames, test.msg)
   182  		}
   183  	}
   184  }
   185  
   186  func TestValidateTransportServerHost(t *testing.T) {
   187  	tests := []struct {
   188  		host                     string
   189  		isTLSPassthroughListener bool
   190  	}{
   191  		{
   192  			host:                     "",
   193  			isTLSPassthroughListener: false,
   194  		},
   195  		{
   196  			host:                     "nginx.org",
   197  			isTLSPassthroughListener: true,
   198  		},
   199  	}
   200  
   201  	for _, test := range tests {
   202  		allErrs := validateTransportServerHost(test.host, field.NewPath("host"), test.isTLSPassthroughListener)
   203  		if len(allErrs) > 0 {
   204  			t.Errorf("validateTransportServerHost(%q, %v) returned errors %v for valid input", test.host, test.isTLSPassthroughListener, allErrs)
   205  		}
   206  	}
   207  }
   208  
   209  func TestValidateTransportServerLoadBalancingMethod(t *testing.T) {
   210  	tests := []struct {
   211  		method   string
   212  		isPlus   bool
   213  		hasError bool
   214  	}{
   215  		{
   216  			method:   "",
   217  			isPlus:   false,
   218  			hasError: false,
   219  		},
   220  		{
   221  			method:   "",
   222  			isPlus:   true,
   223  			hasError: false,
   224  		},
   225  		{
   226  			method:   "hash",
   227  			isPlus:   false,
   228  			hasError: true,
   229  		},
   230  		{
   231  			method:   "hash ${remote_addr}",
   232  			isPlus:   false,
   233  			hasError: false,
   234  		},
   235  		{
   236  			method:   "hash ${remote_addr}AAA",
   237  			isPlus:   false,
   238  			hasError: false,
   239  		},
   240  		{
   241  			method:   `hash ${remote_addr}"`,
   242  			isPlus:   false,
   243  			hasError: true,
   244  		},
   245  		{
   246  			method:   "hash ${invalid_var}",
   247  			isPlus:   false,
   248  			hasError: true,
   249  		},
   250  		{
   251  			method:   "hash not_var",
   252  			isPlus:   false,
   253  			hasError: false,
   254  		},
   255  		{
   256  			method:   "hash ${remote_addr} toomany",
   257  			isPlus:   false,
   258  			hasError: true,
   259  		},
   260  		{
   261  			method:   "hash ${remote_addr} consistent",
   262  			isPlus:   false,
   263  			hasError: false,
   264  		},
   265  		{
   266  			method:   "hash ${remote_addr} toomany consistent",
   267  			isPlus:   false,
   268  			hasError: true,
   269  		},
   270  		{
   271  			method:   "invalid",
   272  			isPlus:   false,
   273  			hasError: true,
   274  		},
   275  		{
   276  			method:   "least_conn",
   277  			isPlus:   false,
   278  			hasError: false,
   279  		},
   280  		{
   281  			method:   "random",
   282  			isPlus:   false,
   283  			hasError: false,
   284  		},
   285  		{
   286  			method:   "random two",
   287  			isPlus:   false,
   288  			hasError: false,
   289  		},
   290  		{
   291  			method:   "random two least_conn",
   292  			isPlus:   false,
   293  			hasError: false,
   294  		},
   295  		{
   296  			method:   "random two least_time",
   297  			isPlus:   false,
   298  			hasError: true,
   299  		},
   300  		{
   301  			method:   "random two least_time",
   302  			isPlus:   true,
   303  			hasError: true,
   304  		}, {
   305  			method:   "random two least_time=connect",
   306  			isPlus:   true,
   307  			hasError: true,
   308  		},
   309  	}
   310  
   311  	for _, test := range tests {
   312  		allErrs := validateLoadBalancingMethod(test.method, field.NewPath("method"), test.isPlus)
   313  		if !test.hasError && len(allErrs) > 0 {
   314  			t.Errorf("validateLoadBalancingMethod(%q, %v) returned errors %v for valid input", test.method, test.isPlus, allErrs)
   315  		}
   316  		if test.hasError && len(allErrs) < 1 {
   317  			t.Errorf("validateLoadBalancingMethod(%q, %v) failed to return an error for invalid input", test.method, test.isPlus)
   318  		}
   319  	}
   320  }
   321  
   322  func TestValidateTransportServerSnippet(t *testing.T) {
   323  	tests := []struct {
   324  		snippet           string
   325  		isSnippetsEnabled bool
   326  		expectError       bool
   327  	}{
   328  		{
   329  			snippet:           "",
   330  			isSnippetsEnabled: false,
   331  			expectError:       false,
   332  		},
   333  		{
   334  			snippet:           "deny 192.168.1.1;",
   335  			isSnippetsEnabled: false,
   336  			expectError:       true,
   337  		},
   338  		{
   339  			snippet:           "deny 192.168.1.1;",
   340  			isSnippetsEnabled: true,
   341  			expectError:       false,
   342  		},
   343  	}
   344  
   345  	for _, test := range tests {
   346  		allErrs := validateSnippets(test.snippet, field.NewPath("serverSnippet"), test.isSnippetsEnabled)
   347  		if test.expectError {
   348  			if len(allErrs) < 1 {
   349  				t.Errorf("validateSnippets(%q, %v) failed to return an error for invalid input", test.snippet, test.isSnippetsEnabled)
   350  			}
   351  		} else {
   352  			if len(allErrs) > 0 {
   353  				t.Errorf("validateSnippets(%q, %v) returned errors %v for valid input", test.snippet, test.isSnippetsEnabled, allErrs)
   354  			}
   355  		}
   356  	}
   357  }
   358  
   359  func TestValidateTransportServerHostFails(t *testing.T) {
   360  	tests := []struct {
   361  		host                     string
   362  		isTLSPassthroughListener bool
   363  	}{
   364  		{
   365  			host:                     "nginx.org",
   366  			isTLSPassthroughListener: false,
   367  		},
   368  		{
   369  			host:                     "",
   370  			isTLSPassthroughListener: true,
   371  		},
   372  	}
   373  
   374  	for _, test := range tests {
   375  		allErrs := validateTransportServerHost(test.host, field.NewPath("host"), test.isTLSPassthroughListener)
   376  		if len(allErrs) == 0 {
   377  			t.Errorf("validateTransportServerHost(%q, %v) returned no errors for invalid input", test.host, test.isTLSPassthroughListener)
   378  		}
   379  	}
   380  }
   381  
   382  func TestValidateTransportListener(t *testing.T) {
   383  	tests := []struct {
   384  		listener       *v1alpha1.TransportServerListener
   385  		tlsPassthrough bool
   386  	}{
   387  		{
   388  			listener: &v1alpha1.TransportServerListener{
   389  				Name:     "tcp-listener",
   390  				Protocol: "TCP",
   391  			},
   392  			tlsPassthrough: false,
   393  		},
   394  		{
   395  			listener: &v1alpha1.TransportServerListener{
   396  				Name:     "tcp-listener",
   397  				Protocol: "TCP",
   398  			},
   399  			tlsPassthrough: true,
   400  		},
   401  		{
   402  			listener: &v1alpha1.TransportServerListener{
   403  				Name:     "tls-passthrough",
   404  				Protocol: "TLS_PASSTHROUGH",
   405  			},
   406  			tlsPassthrough: true,
   407  		},
   408  	}
   409  
   410  	for _, test := range tests {
   411  		tsv := &TransportServerValidator{
   412  			tlsPassthrough: test.tlsPassthrough,
   413  		}
   414  
   415  		allErrs := tsv.validateTransportListener(test.listener, field.NewPath("listener"))
   416  		if len(allErrs) > 0 {
   417  			t.Errorf("validateTransportListener() returned errors %v for valid input %+v when tlsPassithrough is %v", allErrs, test.listener, test.tlsPassthrough)
   418  		}
   419  	}
   420  }
   421  
   422  func TestValidateTransportListenerFails(t *testing.T) {
   423  	tests := []struct {
   424  		listener       *v1alpha1.TransportServerListener
   425  		tlsPassthrough bool
   426  	}{
   427  		{
   428  			listener: &v1alpha1.TransportServerListener{
   429  				Name:     "tls-passthrough",
   430  				Protocol: "TLS_PASSTHROUGH",
   431  			},
   432  			tlsPassthrough: false,
   433  		},
   434  		{
   435  			listener: &v1alpha1.TransportServerListener{
   436  				Name:     "tls-passthrough",
   437  				Protocol: "abc",
   438  			},
   439  			tlsPassthrough: true,
   440  		},
   441  		{
   442  			listener: &v1alpha1.TransportServerListener{
   443  				Name:     "tls-passthrough",
   444  				Protocol: "abc",
   445  			},
   446  			tlsPassthrough: false,
   447  		},
   448  		{
   449  			listener: &v1alpha1.TransportServerListener{
   450  				Name:     "abc",
   451  				Protocol: "TLS_PASSTHROUGH",
   452  			},
   453  			tlsPassthrough: true,
   454  		},
   455  		{
   456  			listener: &v1alpha1.TransportServerListener{
   457  				Name:     "abc",
   458  				Protocol: "TLS_PASSTHROUGH",
   459  			},
   460  			tlsPassthrough: false,
   461  		},
   462  	}
   463  
   464  	for _, test := range tests {
   465  		tsv := &TransportServerValidator{
   466  			tlsPassthrough: test.tlsPassthrough,
   467  		}
   468  
   469  		allErrs := tsv.validateTransportListener(test.listener, field.NewPath("listener"))
   470  		if len(allErrs) == 0 {
   471  			t.Errorf("validateTransportListener() returned no errors for invalid input %+v when tlsPassthrough is %v", test.listener, test.tlsPassthrough)
   472  		}
   473  	}
   474  }
   475  
   476  func TestValidateIsPotentialTLSPassthroughListener(t *testing.T) {
   477  	tests := []struct {
   478  		listener *v1alpha1.TransportServerListener
   479  		expected bool
   480  	}{
   481  		{
   482  			listener: &v1alpha1.TransportServerListener{
   483  				Name:     "tls-passthrough",
   484  				Protocol: "abc",
   485  			},
   486  			expected: true,
   487  		},
   488  		{
   489  			listener: &v1alpha1.TransportServerListener{
   490  				Name:     "abc",
   491  				Protocol: "TLS_PASSTHROUGH",
   492  			},
   493  			expected: true,
   494  		},
   495  		{
   496  			listener: &v1alpha1.TransportServerListener{
   497  				Name:     "tcp",
   498  				Protocol: "TCP",
   499  			},
   500  			expected: false,
   501  		},
   502  	}
   503  
   504  	for _, test := range tests {
   505  		result := isPotentialTLSPassthroughListener(test.listener)
   506  		if result != test.expected {
   507  			t.Errorf("isPotentialTLSPassthroughListener(%+v) returned %v but expected %v", test.listener, result, test.expected)
   508  		}
   509  	}
   510  }
   511  
   512  func TestValidateListenerProtocol(t *testing.T) {
   513  	validProtocols := []string{
   514  		"TCP",
   515  		"UDP",
   516  	}
   517  
   518  	for _, p := range validProtocols {
   519  		allErrs := validateListenerProtocol(p, field.NewPath("protocol"))
   520  		if len(allErrs) > 0 {
   521  			t.Errorf("validateListenerProtocol(%q) returned errors %v for valid input", p, allErrs)
   522  		}
   523  	}
   524  
   525  	invalidProtocols := []string{
   526  		"",
   527  		"HTTP",
   528  		"udp",
   529  		"UDP ",
   530  	}
   531  
   532  	for _, p := range invalidProtocols {
   533  		allErrs := validateListenerProtocol(p, field.NewPath("protocol"))
   534  		if len(allErrs) == 0 {
   535  			t.Errorf("validateListenerProtocol(%q) returned no errors for invalid input", p)
   536  		}
   537  	}
   538  }
   539  
   540  func TestValidateTSUpstreamHealthChecks(t *testing.T) {
   541  	tests := []struct {
   542  		healthCheck *v1alpha1.HealthCheck
   543  		msg         string
   544  	}{
   545  		{
   546  			healthCheck: nil,
   547  			msg:         "nil health check",
   548  		},
   549  		{
   550  			healthCheck: &v1alpha1.HealthCheck{},
   551  			msg:         "non nil health check",
   552  		},
   553  		{
   554  			healthCheck: &v1alpha1.HealthCheck{
   555  				Enabled:  true,
   556  				Timeout:  "30s",
   557  				Jitter:   "5s",
   558  				Port:     88,
   559  				Interval: "10",
   560  				Passes:   3,
   561  				Fails:    4,
   562  			},
   563  			msg: "valid Health check",
   564  		},
   565  	}
   566  	for _, test := range tests {
   567  		allErrs := validateTSUpstreamHealthChecks(test.healthCheck, field.NewPath("healthCheck"))
   568  		if len(allErrs) > 0 {
   569  			t.Errorf("validateTSUpstreamHealthChecks() returned errors %v  for valid input for the case of %s", allErrs, test.msg)
   570  		}
   571  	}
   572  }
   573  
   574  func TestValidateTSUpstreamHealthChecksFails(t *testing.T) {
   575  	tests := []struct {
   576  		healthCheck *v1alpha1.HealthCheck
   577  		msg         string
   578  	}{
   579  		{
   580  			healthCheck: &v1alpha1.HealthCheck{
   581  				Enabled:  true,
   582  				Timeout:  "-30s",
   583  				Jitter:   "5s",
   584  				Port:     88,
   585  				Interval: "10",
   586  				Passes:   3,
   587  				Fails:    4,
   588  			},
   589  			msg: "invalid timeout",
   590  		},
   591  		{
   592  			healthCheck: &v1alpha1.HealthCheck{
   593  				Enabled:  true,
   594  				Timeout:  "30s",
   595  				Jitter:   "5s",
   596  				Port:     4000000000000000,
   597  				Interval: "10",
   598  				Passes:   3,
   599  				Fails:    4,
   600  			},
   601  			msg: "invalid port number",
   602  		},
   603  		{
   604  			healthCheck: &v1alpha1.HealthCheck{
   605  				Enabled:  true,
   606  				Timeout:  "30s",
   607  				Jitter:   "5s",
   608  				Port:     40,
   609  				Interval: "10",
   610  				Passes:   -3,
   611  				Fails:    4,
   612  			},
   613  			msg: "invalid passes value",
   614  		},
   615  		{
   616  			healthCheck: &v1alpha1.HealthCheck{
   617  				Enabled:  true,
   618  				Timeout:  "30s",
   619  				Jitter:   "5s",
   620  				Port:     40,
   621  				Interval: "10",
   622  				Passes:   3,
   623  				Fails:    -4,
   624  			},
   625  			msg: "invalid fails value",
   626  		},
   627  		{
   628  			healthCheck: &v1alpha1.HealthCheck{
   629  				Enabled:  true,
   630  				Timeout:  "30s",
   631  				Jitter:   "5s",
   632  				Port:     40,
   633  				Interval: "ten",
   634  				Passes:   3,
   635  				Fails:    4,
   636  			},
   637  			msg: "invalid interval value",
   638  		},
   639  		{
   640  			healthCheck: &v1alpha1.HealthCheck{
   641  				Enabled:  true,
   642  				Timeout:  "30s",
   643  				Jitter:   "5sec",
   644  				Port:     40,
   645  				Interval: "10",
   646  				Passes:   3,
   647  				Fails:    4,
   648  			},
   649  			msg: "invalid jitter value",
   650  		},
   651  	}
   652  
   653  	for _, test := range tests {
   654  		allErrs := validateTSUpstreamHealthChecks(test.healthCheck, field.NewPath("healthCheck"))
   655  		if len(allErrs) == 0 {
   656  			t.Errorf("validateTSUpstreamHealthChecks() returned no error for invalid input %v", test.msg)
   657  		}
   658  	}
   659  }
   660  
   661  func TestValidateUpstreamParameters(t *testing.T) {
   662  	tests := []struct {
   663  		parameters *v1alpha1.UpstreamParameters
   664  		msg        string
   665  	}{
   666  		{
   667  			parameters: nil,
   668  			msg:        "nil parameters",
   669  		},
   670  		{
   671  			parameters: &v1alpha1.UpstreamParameters{},
   672  			msg:        "Non-nil parameters",
   673  		},
   674  	}
   675  
   676  	for _, test := range tests {
   677  		allErrs := validateTransportServerUpstreamParameters(test.parameters, field.NewPath("upstreamParameters"), "UDP")
   678  		if len(allErrs) > 0 {
   679  			t.Errorf("validateTransportServerUpstreamParameters() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   680  		}
   681  	}
   682  }
   683  
   684  func TestValidateSessionParameters(t *testing.T) {
   685  	tests := []struct {
   686  		parameters *v1alpha1.SessionParameters
   687  		msg        string
   688  	}{
   689  		{
   690  			parameters: nil,
   691  			msg:        "nil parameters",
   692  		},
   693  		{
   694  			parameters: &v1alpha1.SessionParameters{},
   695  			msg:        "Non-nil parameters",
   696  		},
   697  		{
   698  			parameters: &v1alpha1.SessionParameters{
   699  				Timeout: "60s",
   700  			},
   701  			msg: "valid parameters",
   702  		},
   703  	}
   704  
   705  	for _, test := range tests {
   706  		allErrs := validateSessionParameters(test.parameters, field.NewPath("sessionParameters"))
   707  		if len(allErrs) > 0 {
   708  			t.Errorf("validateSessionParameters() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   709  		}
   710  	}
   711  }
   712  
   713  func TestValidateSessionParametersFails(t *testing.T) {
   714  	tests := []struct {
   715  		parameters *v1alpha1.SessionParameters
   716  		msg        string
   717  	}{
   718  		{
   719  			parameters: &v1alpha1.SessionParameters{
   720  				Timeout: "-1s",
   721  			},
   722  			msg: "invalid timeout",
   723  		},
   724  	}
   725  
   726  	for _, test := range tests {
   727  		allErrs := validateSessionParameters(test.parameters, field.NewPath("sessionParameters"))
   728  		if len(allErrs) == 0 {
   729  			t.Errorf("validateSessionParameters() returned no errors for invalid input: %v", test.msg)
   730  		}
   731  	}
   732  }
   733  
   734  func TestValidateUDPUpstreamParameter(t *testing.T) {
   735  	validInput := []struct {
   736  		parameter *int
   737  		protocol  string
   738  	}{
   739  		{
   740  			parameter: nil,
   741  			protocol:  "TCP",
   742  		},
   743  		{
   744  			parameter: nil,
   745  			protocol:  "UDP",
   746  		},
   747  		{
   748  			parameter: createPointerFromInt(0),
   749  			protocol:  "UDP",
   750  		},
   751  		{
   752  			parameter: createPointerFromInt(1),
   753  			protocol:  "UDP",
   754  		},
   755  	}
   756  
   757  	for _, input := range validInput {
   758  		allErrs := validateUDPUpstreamParameter(input.parameter, field.NewPath("parameter"), input.protocol)
   759  		if len(allErrs) > 0 {
   760  			t.Errorf("validateUDPUpstreamParameter(%v, %q) returned errors %v for valid input", input.parameter, input.protocol, allErrs)
   761  		}
   762  	}
   763  }
   764  
   765  func TestValidateUDPUpstreamParameterFails(t *testing.T) {
   766  	invalidInput := []struct {
   767  		parameter *int
   768  		protocol  string
   769  	}{
   770  		{
   771  			parameter: createPointerFromInt(0),
   772  			protocol:  "TCP",
   773  		},
   774  		{
   775  			parameter: createPointerFromInt(-1),
   776  			protocol:  "UDP",
   777  		},
   778  	}
   779  
   780  	for _, input := range invalidInput {
   781  		allErrs := validateUDPUpstreamParameter(input.parameter, field.NewPath("parameter"), input.protocol)
   782  		if len(allErrs) == 0 {
   783  			t.Errorf("validateUDPUpstreamParameter(%v, %q) returned no errors for invalid input", input.parameter, input.protocol)
   784  		}
   785  	}
   786  }
   787  
   788  func TestValidateTransportServerAction(t *testing.T) {
   789  	upstreamNames := map[string]sets.Empty{
   790  		"test": {},
   791  	}
   792  
   793  	action := &v1alpha1.Action{
   794  		Pass: "test",
   795  	}
   796  
   797  	allErrs := validateTransportServerAction(action, field.NewPath("action"), upstreamNames)
   798  	if len(allErrs) > 0 {
   799  		t.Errorf("validateTransportServerAction() returned errors %v for valid input", allErrs)
   800  	}
   801  }
   802  
   803  func TestValidateTransportServerActionFails(t *testing.T) {
   804  	upstreamNames := map[string]sets.Empty{}
   805  
   806  	tests := []struct {
   807  		action *v1alpha1.Action
   808  		msg    string
   809  	}{
   810  		{
   811  			action: &v1alpha1.Action{
   812  				Pass: "",
   813  			},
   814  			msg: "missing pass field",
   815  		},
   816  		{
   817  			action: &v1alpha1.Action{
   818  				Pass: "non-existing",
   819  			},
   820  			msg: "pass references a non-existing upstream",
   821  		},
   822  	}
   823  
   824  	for _, test := range tests {
   825  		allErrs := validateTransportServerAction(test.action, field.NewPath("action"), upstreamNames)
   826  		if len(allErrs) == 0 {
   827  			t.Errorf("validateTransportServerAction() returned no errors for invalid input for the case of %s", test.msg)
   828  		}
   829  	}
   830  }
   831  
   832  func TestValidateMatchSend(t *testing.T) {
   833  	validInput := []string{
   834  		"",
   835  		"abc",
   836  		"hello${world}",
   837  		`hello\x00`,
   838  	}
   839  	invalidInput := []string{
   840  		`hello"world`,
   841  		`\x1x`,
   842  	}
   843  
   844  	for _, send := range validInput {
   845  		allErrs := validateMatchSend(send, field.NewPath("send"))
   846  		if len(allErrs) > 0 {
   847  			t.Errorf("validateMatchSend(%q) returned errors %v for valid input", send, allErrs)
   848  		}
   849  	}
   850  	for _, send := range invalidInput {
   851  		allErrs := validateMatchSend(send, field.NewPath("send"))
   852  		if len(allErrs) == 0 {
   853  			t.Errorf("validateMatchSend(%q) returned no errors for invalid input", send)
   854  		}
   855  	}
   856  }
   857  
   858  func TestValidateHexString(t *testing.T) {
   859  	validInput := []string{
   860  		"",
   861  		"abc",
   862  		`\x00`,
   863  		`\xaa`,
   864  		`\xaA`,
   865  		`\xff`,
   866  		`\xaaFFabc\x12`,
   867  	}
   868  	invalidInput := []string{
   869  		`\x`,
   870  		`\x1`,
   871  		`\xax`,
   872  		`\x\b`,
   873  		`\xaaFFabc\xx12`, // \xx1 is invalid
   874  	}
   875  
   876  	for _, s := range validInput {
   877  		err := validateHexString(s)
   878  		if err != nil {
   879  			t.Errorf("validateHexString(%q) returned error %v for valid input", s, err)
   880  		}
   881  	}
   882  	for _, s := range invalidInput {
   883  		err := validateHexString(s)
   884  		if err == nil {
   885  			t.Errorf("validateHexString(%q) returned no error for invalid input", s)
   886  		}
   887  	}
   888  }
   889  
   890  func TestValidateMatchExpect(t *testing.T) {
   891  	validInput := []string{
   892  		``,
   893  		`abc`,
   894  		`abc\x00`,
   895  		`~* 200 OK`,
   896  		`~ 2\d\d`,
   897  		`~`,
   898  		`~*`,
   899  	}
   900  	invalidInput := []string{
   901  		`hello"world`,
   902  		`~hello"world`,
   903  		`~*hello"world`,
   904  		`\x1x`,
   905  		`~\x1x`,
   906  		`~*\x1x`,
   907  		`~[{`,
   908  		`~{1}`,
   909  	}
   910  
   911  	for _, input := range validInput {
   912  		allErrs := validateMatchExpect(input, field.NewPath("expect"))
   913  		if len(allErrs) > 0 {
   914  			t.Errorf("validateMatchExpect(%q) returned errors %v for valid input", input, allErrs)
   915  		}
   916  	}
   917  	for _, input := range invalidInput {
   918  		allErrs := validateMatchExpect(input, field.NewPath("expect"))
   919  		if len(allErrs) == 0 {
   920  			t.Errorf("validateMatchExpect(%q) returned no errors for invalid input", input)
   921  		}
   922  	}
   923  }