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

     1  package validation
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
     8  	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  	"k8s.io/apimachinery/pkg/util/sets"
    10  	"k8s.io/apimachinery/pkg/util/validation/field"
    11  )
    12  
    13  func TestValidateVirtualServer(t *testing.T) {
    14  	virtualServer := v1.VirtualServer{
    15  		ObjectMeta: meta_v1.ObjectMeta{
    16  			Name:      "cafe",
    17  			Namespace: "default",
    18  		},
    19  		Spec: v1.VirtualServerSpec{
    20  			Host: "example.com",
    21  			TLS: &v1.TLS{
    22  				Secret: "abc",
    23  			},
    24  			Upstreams: []v1.Upstream{
    25  				{
    26  					Name:      "first",
    27  					Service:   "service-1",
    28  					LBMethod:  "random",
    29  					Port:      80,
    30  					MaxFails:  createPointerFromInt(8),
    31  					MaxConns:  createPointerFromInt(16),
    32  					Keepalive: createPointerFromInt(32),
    33  				},
    34  				{
    35  					Name:    "second",
    36  					Service: "service-2",
    37  					Port:    80,
    38  				},
    39  			},
    40  			Routes: []v1.Route{
    41  				{
    42  					Path: "/first",
    43  					Action: &v1.Action{
    44  						Pass: "first",
    45  					},
    46  				},
    47  				{
    48  					Path: "/second",
    49  					Action: &v1.Action{
    50  						Pass: "second",
    51  					},
    52  				},
    53  			},
    54  		},
    55  	}
    56  
    57  	vsv := &VirtualServerValidator{isPlus: false}
    58  
    59  	err := vsv.ValidateVirtualServer(&virtualServer)
    60  	if err != nil {
    61  		t.Errorf("ValidateVirtualServer() returned error %v for valid input %v", err, virtualServer)
    62  	}
    63  }
    64  
    65  func TestValidateHost(t *testing.T) {
    66  	validHosts := []string{
    67  		"hello",
    68  		"example.com",
    69  		"hello-world-1",
    70  	}
    71  
    72  	for _, h := range validHosts {
    73  		allErrs := validateHost(h, field.NewPath("host"))
    74  		if len(allErrs) > 0 {
    75  			t.Errorf("validateHost(%q) returned errors %v for valid input", h, allErrs)
    76  		}
    77  	}
    78  
    79  	invalidHosts := []string{
    80  		"",
    81  		"*",
    82  		"..",
    83  		".example.com",
    84  		"-hello-world-1",
    85  	}
    86  
    87  	for _, h := range invalidHosts {
    88  		allErrs := validateHost(h, field.NewPath("host"))
    89  		if len(allErrs) == 0 {
    90  			t.Errorf("validateHost(%q) returned no errors for invalid input", h)
    91  		}
    92  	}
    93  }
    94  
    95  func TestValidatePolicies(t *testing.T) {
    96  	tests := []struct {
    97  		policies []v1.PolicyReference
    98  		msg      string
    99  	}{
   100  		{
   101  			policies: []v1.PolicyReference{
   102  				{
   103  					Name: "my-policy",
   104  				},
   105  			},
   106  			msg: "name without namespace",
   107  		},
   108  		{
   109  			policies: []v1.PolicyReference{
   110  				{
   111  					Name:      "my-policy",
   112  					Namespace: "nginx-ingress",
   113  				},
   114  			},
   115  			msg: "name with namespace",
   116  		},
   117  		{
   118  			policies: []v1.PolicyReference{
   119  				{
   120  					Name:      "my-policy",
   121  					Namespace: "default",
   122  				},
   123  				{
   124  					Name:      "my-policy",
   125  					Namespace: "test",
   126  				},
   127  			},
   128  			msg: "same name different namespaces",
   129  		},
   130  	}
   131  
   132  	for _, test := range tests {
   133  		allErrs := validatePolicies(test.policies, field.NewPath("policies"), "default")
   134  		if len(allErrs) > 0 {
   135  			t.Errorf("validatePolicies() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   136  		}
   137  	}
   138  }
   139  
   140  func TestValidatePoliciesFails(t *testing.T) {
   141  	tests := []struct {
   142  		policies []v1.PolicyReference
   143  		msg      string
   144  	}{
   145  		{
   146  			policies: []v1.PolicyReference{
   147  				{
   148  					Name: "",
   149  				},
   150  			},
   151  			msg: "missing name",
   152  		},
   153  		{
   154  			policies: []v1.PolicyReference{
   155  				{
   156  					Name: "-invalid",
   157  				},
   158  			},
   159  			msg: "invalid name",
   160  		},
   161  		{
   162  			policies: []v1.PolicyReference{
   163  				{
   164  					Name:      "my-policy",
   165  					Namespace: "-invalid",
   166  				},
   167  			},
   168  			msg: "invalid namespace",
   169  		},
   170  		{
   171  			policies: []v1.PolicyReference{
   172  				{
   173  					Name:      "my-policy",
   174  					Namespace: "default",
   175  				},
   176  				{
   177  					Name:      "my-policy",
   178  					Namespace: "default",
   179  				},
   180  			},
   181  			msg: "duplicated policies",
   182  		},
   183  		{
   184  			policies: []v1.PolicyReference{
   185  				{
   186  					Name:      "my-policy",
   187  					Namespace: "default",
   188  				},
   189  				{
   190  					Name: "my-policy",
   191  				},
   192  			},
   193  			msg: "duplicated policies with inferred namespace",
   194  		},
   195  	}
   196  
   197  	for _, test := range tests {
   198  		allErrs := validatePolicies(test.policies, field.NewPath("policies"), "default")
   199  		if len(allErrs) == 0 {
   200  			t.Errorf("validatePolicies() returned no errors for invalid input for the case of %s", test.msg)
   201  		}
   202  	}
   203  }
   204  
   205  func TestValidateTLS(t *testing.T) {
   206  	validTLSes := []*v1.TLS{
   207  		nil,
   208  		{
   209  			Secret: "",
   210  		},
   211  		{
   212  			Secret: "my-secret",
   213  		},
   214  		{
   215  			Secret:   "my-secret",
   216  			Redirect: &v1.TLSRedirect{},
   217  		},
   218  		{
   219  			Secret: "my-secret",
   220  			Redirect: &v1.TLSRedirect{
   221  				Enable: true,
   222  			},
   223  		},
   224  		{
   225  			Secret: "my-secret",
   226  			Redirect: &v1.TLSRedirect{
   227  				Enable:  true,
   228  				Code:    createPointerFromInt(302),
   229  				BasedOn: "scheme",
   230  			},
   231  		},
   232  		{
   233  			Secret: "my-secret",
   234  			Redirect: &v1.TLSRedirect{
   235  				Enable: true,
   236  				Code:   createPointerFromInt(307),
   237  			},
   238  		},
   239  	}
   240  
   241  	for _, tls := range validTLSes {
   242  		allErrs := validateTLS(tls, field.NewPath("tls"))
   243  		if len(allErrs) > 0 {
   244  			t.Errorf("validateTLS() returned errors %v for valid input %v", allErrs, tls)
   245  		}
   246  	}
   247  
   248  	invalidTLSes := []*v1.TLS{
   249  		{
   250  			Secret: "-",
   251  		},
   252  		{
   253  			Secret: "a/b",
   254  		},
   255  		{
   256  			Secret: "my-secret",
   257  			Redirect: &v1.TLSRedirect{
   258  				Enable:  true,
   259  				Code:    createPointerFromInt(305),
   260  				BasedOn: "scheme",
   261  			},
   262  		},
   263  		{
   264  			Secret: "my-secret",
   265  			Redirect: &v1.TLSRedirect{
   266  				Enable:  true,
   267  				Code:    createPointerFromInt(301),
   268  				BasedOn: "invalidScheme",
   269  			},
   270  		},
   271  	}
   272  
   273  	for _, tls := range invalidTLSes {
   274  		allErrs := validateTLS(tls, field.NewPath("tls"))
   275  		if len(allErrs) == 0 {
   276  			t.Errorf("validateTLS() returned no errors for invalid input %v", tls)
   277  		}
   278  	}
   279  }
   280  
   281  func TestValidateUpstreams(t *testing.T) {
   282  	tests := []struct {
   283  		upstreams             []v1.Upstream
   284  		expectedUpstreamNames sets.String
   285  		msg                   string
   286  	}{
   287  		{
   288  			upstreams:             []v1.Upstream{},
   289  			expectedUpstreamNames: sets.String{},
   290  			msg:                   "no upstreams",
   291  		},
   292  		{
   293  			upstreams: []v1.Upstream{
   294  				{
   295  					Name:                     "upstream1",
   296  					Service:                  "test-1",
   297  					Port:                     80,
   298  					ProxyNextUpstream:        "error timeout",
   299  					ProxyNextUpstreamTimeout: "10s",
   300  					ProxyNextUpstreamTries:   5,
   301  					MaxConns:                 createPointerFromInt(16),
   302  				},
   303  				{
   304  					Name:                     "upstream2",
   305  					Subselector:              map[string]string{"version": "test"},
   306  					Service:                  "test-2",
   307  					Port:                     80,
   308  					ProxyNextUpstream:        "error timeout",
   309  					ProxyNextUpstreamTimeout: "10s",
   310  					ProxyNextUpstreamTries:   5,
   311  				},
   312  				{
   313  					Name:         "upstream3",
   314  					Service:      "test-3",
   315  					Port:         80,
   316  					UseClusterIP: true,
   317  				},
   318  			},
   319  			expectedUpstreamNames: map[string]sets.Empty{
   320  				"upstream1": {},
   321  				"upstream2": {},
   322  				"upstream3": {},
   323  			},
   324  			msg: "2 valid upstreams",
   325  		},
   326  	}
   327  
   328  	vsv := &VirtualServerValidator{isPlus: false}
   329  
   330  	for _, test := range tests {
   331  		allErrs, resultUpstreamNames := vsv.validateUpstreams(test.upstreams, field.NewPath("upstreams"))
   332  		if len(allErrs) > 0 {
   333  			t.Errorf("validateUpstreams() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   334  		}
   335  		if !resultUpstreamNames.Equal(test.expectedUpstreamNames) {
   336  			t.Errorf("validateUpstreams() returned %v expected %v for the case of %s", resultUpstreamNames, test.expectedUpstreamNames, test.msg)
   337  		}
   338  	}
   339  }
   340  
   341  func TestValidateUpstreamsFails(t *testing.T) {
   342  	tests := []struct {
   343  		upstreams             []v1.Upstream
   344  		expectedUpstreamNames sets.String
   345  		msg                   string
   346  	}{
   347  		{
   348  			upstreams: []v1.Upstream{
   349  				{
   350  					Name:                     "@upstream1",
   351  					Service:                  "test-1",
   352  					Port:                     80,
   353  					ProxyNextUpstream:        "http_502",
   354  					ProxyNextUpstreamTimeout: "10s",
   355  					ProxyNextUpstreamTries:   5,
   356  				},
   357  			},
   358  			expectedUpstreamNames: sets.String{},
   359  			msg:                   "invalid upstream name",
   360  		},
   361  		{
   362  			upstreams: []v1.Upstream{
   363  				{
   364  					Name:                     "upstream1",
   365  					Service:                  "@test-1",
   366  					Port:                     80,
   367  					ProxyNextUpstream:        "error timeout",
   368  					ProxyNextUpstreamTimeout: "10s",
   369  					ProxyNextUpstreamTries:   5,
   370  				},
   371  			},
   372  			expectedUpstreamNames: map[string]sets.Empty{
   373  				"upstream1": {},
   374  			},
   375  			msg: "invalid service",
   376  		},
   377  		{
   378  			upstreams: []v1.Upstream{
   379  				{
   380  					Name:                     "upstream1",
   381  					Service:                  "test-1",
   382  					Port:                     0,
   383  					ProxyNextUpstream:        "error timeout",
   384  					ProxyNextUpstreamTimeout: "10s",
   385  					ProxyNextUpstreamTries:   5,
   386  				},
   387  			},
   388  			expectedUpstreamNames: map[string]sets.Empty{
   389  				"upstream1": {},
   390  			},
   391  			msg: "invalid port",
   392  		},
   393  		{
   394  			upstreams: []v1.Upstream{
   395  				{
   396  					Name:                     "upstream1",
   397  					Service:                  "test-1",
   398  					Port:                     80,
   399  					ProxyNextUpstream:        "error timeout",
   400  					ProxyNextUpstreamTimeout: "10s",
   401  					ProxyNextUpstreamTries:   5,
   402  				},
   403  				{
   404  					Name:                     "upstream1",
   405  					Service:                  "test-2",
   406  					Port:                     80,
   407  					ProxyNextUpstream:        "error timeout",
   408  					ProxyNextUpstreamTimeout: "10s",
   409  					ProxyNextUpstreamTries:   5,
   410  				},
   411  			},
   412  			expectedUpstreamNames: map[string]sets.Empty{
   413  				"upstream1": {},
   414  			},
   415  			msg: "duplicated upstreams",
   416  		},
   417  		{
   418  			upstreams: []v1.Upstream{
   419  				{
   420  					Name:                     "upstream1",
   421  					Service:                  "test-1",
   422  					Port:                     80,
   423  					ProxyNextUpstream:        "https_504",
   424  					ProxyNextUpstreamTimeout: "10s",
   425  					ProxyNextUpstreamTries:   5,
   426  				},
   427  			},
   428  			expectedUpstreamNames: map[string]sets.Empty{
   429  				"upstream1": {},
   430  			},
   431  			msg: "invalid next upstream syntax",
   432  		},
   433  		{
   434  			upstreams: []v1.Upstream{
   435  				{
   436  					Name:                     "upstream1",
   437  					Service:                  "test-1",
   438  					Port:                     80,
   439  					ProxyNextUpstream:        "http_504",
   440  					ProxyNextUpstreamTimeout: "-2s",
   441  					ProxyNextUpstreamTries:   5,
   442  				},
   443  			},
   444  			expectedUpstreamNames: map[string]sets.Empty{
   445  				"upstream1": {},
   446  			},
   447  			msg: "invalid upstream timeout value",
   448  		},
   449  		{
   450  			upstreams: []v1.Upstream{
   451  				{
   452  					Name:                     "upstream1",
   453  					Service:                  "test-1",
   454  					Port:                     80,
   455  					ProxyNextUpstream:        "https_504",
   456  					ProxyNextUpstreamTimeout: "10s",
   457  					ProxyNextUpstreamTries:   -1,
   458  				},
   459  			},
   460  			expectedUpstreamNames: map[string]sets.Empty{
   461  				"upstream1": {},
   462  			},
   463  			msg: "invalid upstream tries value",
   464  		},
   465  		{
   466  			upstreams: []v1.Upstream{
   467  				{
   468  					Name:     "upstream1",
   469  					Service:  "test-1",
   470  					Port:     80,
   471  					MaxConns: createPointerFromInt(-1),
   472  				},
   473  			},
   474  			expectedUpstreamNames: map[string]sets.Empty{
   475  				"upstream1": {},
   476  			},
   477  			msg: "negative value for MaxConns",
   478  		},
   479  		{
   480  			upstreams: []v1.Upstream{
   481  				{
   482  					Name:              "upstream1",
   483  					Service:           "test-1",
   484  					Port:              80,
   485  					ClientMaxBodySize: "7mins",
   486  				},
   487  			},
   488  			expectedUpstreamNames: map[string]sets.Empty{
   489  				"upstream1": {},
   490  			},
   491  			msg: "invalid value for ClientMaxBodySize",
   492  		},
   493  		{
   494  			upstreams: []v1.Upstream{
   495  				{
   496  					Name:    "upstream1",
   497  					Service: "test-1",
   498  					Port:    80,
   499  					ProxyBuffers: &v1.UpstreamBuffers{
   500  						Number: -1,
   501  						Size:   "1G",
   502  					},
   503  				},
   504  			},
   505  			expectedUpstreamNames: map[string]sets.Empty{
   506  				"upstream1": {},
   507  			},
   508  			msg: "invalid value for ProxyBuffers",
   509  		},
   510  		{
   511  			upstreams: []v1.Upstream{
   512  				{
   513  					Name:            "upstream1",
   514  					Service:         "test-1",
   515  					Port:            80,
   516  					ProxyBufferSize: "1G",
   517  				},
   518  			},
   519  			expectedUpstreamNames: map[string]sets.Empty{
   520  				"upstream1": {},
   521  			},
   522  			msg: "invalid value for ProxyBufferSize",
   523  		},
   524  		{
   525  			upstreams: []v1.Upstream{
   526  				{
   527  					Name:        "upstream1",
   528  					Service:     "test-1",
   529  					Subselector: map[string]string{"\\$invalidkey": "test"},
   530  					Port:        80,
   531  				},
   532  			},
   533  			expectedUpstreamNames: map[string]sets.Empty{
   534  				"upstream1": {},
   535  			},
   536  			msg: "invalid key for subselector",
   537  		},
   538  		{
   539  			upstreams: []v1.Upstream{
   540  				{
   541  					Name:        "upstream1",
   542  					Service:     "test-1",
   543  					Subselector: map[string]string{"version": "test=fail"},
   544  					Port:        80,
   545  				},
   546  			},
   547  			expectedUpstreamNames: map[string]sets.Empty{
   548  				"upstream1": {},
   549  			},
   550  			msg: "invalid value for subselector",
   551  		},
   552  		{
   553  			upstreams: []v1.Upstream{
   554  				{
   555  					Name:         "upstream1",
   556  					Service:      "test-1",
   557  					Subselector:  map[string]string{"version": "test"},
   558  					UseClusterIP: true,
   559  					Port:         80,
   560  				},
   561  			},
   562  			expectedUpstreamNames: map[string]sets.Empty{
   563  				"upstream1": {},
   564  			},
   565  			msg: "invalid use of subselector with use-cluster-ip",
   566  		},
   567  	}
   568  
   569  	vsv := &VirtualServerValidator{isPlus: false}
   570  
   571  	for _, test := range tests {
   572  		allErrs, resultUpstreamNames := vsv.validateUpstreams(test.upstreams, field.NewPath("upstreams"))
   573  		if len(allErrs) == 0 {
   574  			t.Errorf("validateUpstreams() returned no errors for the case of %s", test.msg)
   575  		}
   576  		if !resultUpstreamNames.Equal(test.expectedUpstreamNames) {
   577  			t.Errorf("validateUpstreams() returned %v expected %v for the case of %s", resultUpstreamNames, test.expectedUpstreamNames, test.msg)
   578  		}
   579  	}
   580  }
   581  
   582  func TestValidateNextUpstream(t *testing.T) {
   583  	tests := []struct {
   584  		inputS string
   585  	}{
   586  		{
   587  			inputS: "error timeout",
   588  		},
   589  		{
   590  			inputS: "http_404 timeout",
   591  		},
   592  	}
   593  	for _, test := range tests {
   594  		allErrs := validateNextUpstream(test.inputS, field.NewPath("next-upstreams"))
   595  		if len(allErrs) > 0 {
   596  			t.Errorf("validateNextUpstream(%q) returned errors %v for valid input.", test.inputS, allErrs)
   597  		}
   598  	}
   599  }
   600  
   601  func TestValidateNextUpstreamFails(t *testing.T) {
   602  	tests := []struct {
   603  		inputS string
   604  	}{
   605  		{
   606  			inputS: "error error",
   607  		},
   608  		{
   609  			inputS: "https_404",
   610  		},
   611  	}
   612  	for _, test := range tests {
   613  		allErrs := validateNextUpstream(test.inputS, field.NewPath("next-upstreams"))
   614  		if len(allErrs) == 0 {
   615  			t.Errorf("validateNextUpstream(%q) didn't return errors %v for invalid input.", test.inputS, allErrs)
   616  		}
   617  	}
   618  }
   619  
   620  func TestValidateDNS1035Label(t *testing.T) {
   621  	validNames := []string{
   622  		"test",
   623  		"test-123",
   624  	}
   625  
   626  	for _, name := range validNames {
   627  		allErrs := validateDNS1035Label(name, field.NewPath("name"))
   628  		if len(allErrs) > 0 {
   629  			t.Errorf("validateDNS1035Label(%q) returned errors %v for valid input", name, allErrs)
   630  		}
   631  	}
   632  
   633  	invalidNames := []string{
   634  		"",
   635  		"123",
   636  		"test.123",
   637  	}
   638  
   639  	for _, name := range invalidNames {
   640  		allErrs := validateDNS1035Label(name, field.NewPath("name"))
   641  		if len(allErrs) == 0 {
   642  			t.Errorf("validateDNS1035Label(%q) returned no errors for invalid input", name)
   643  		}
   644  	}
   645  }
   646  
   647  func TestValidateVirtualServerRoutes(t *testing.T) {
   648  	tests := []struct {
   649  		routes        []v1.Route
   650  		upstreamNames sets.String
   651  		msg           string
   652  	}{
   653  		{
   654  			routes:        []v1.Route{},
   655  			upstreamNames: sets.String{},
   656  			msg:           "no routes",
   657  		},
   658  		{
   659  			routes: []v1.Route{
   660  				{
   661  					Path: "/",
   662  					Action: &v1.Action{
   663  						Pass: "test",
   664  					},
   665  				},
   666  			},
   667  			upstreamNames: map[string]sets.Empty{
   668  				"test": {},
   669  			},
   670  			msg: "valid route",
   671  		},
   672  	}
   673  
   674  	vsv := &VirtualServerValidator{isPlus: false}
   675  
   676  	for _, test := range tests {
   677  		allErrs := vsv.validateVirtualServerRoutes(test.routes, field.NewPath("routes"), test.upstreamNames, "default")
   678  		if len(allErrs) > 0 {
   679  			t.Errorf("validateVirtualServerRoutes() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   680  		}
   681  	}
   682  }
   683  
   684  func TestValidateVirtualServerRoutesFails(t *testing.T) {
   685  	tests := []struct {
   686  		routes        []v1.Route
   687  		upstreamNames sets.String
   688  		msg           string
   689  	}{
   690  		{
   691  			routes: []v1.Route{
   692  				{
   693  					Path: "/test",
   694  					Action: &v1.Action{
   695  						Pass: "test-1",
   696  					},
   697  				},
   698  				{
   699  					Path: "/test",
   700  					Action: &v1.Action{
   701  						Pass: "test-2",
   702  					},
   703  				},
   704  			},
   705  			upstreamNames: map[string]sets.Empty{
   706  				"test-1": {},
   707  				"test-2": {},
   708  			},
   709  			msg: "duplicated paths",
   710  		},
   711  
   712  		{
   713  			routes: []v1.Route{
   714  				{
   715  					Path:   "",
   716  					Action: nil,
   717  				},
   718  			},
   719  			upstreamNames: map[string]sets.Empty{},
   720  			msg:           "invalid route",
   721  		},
   722  	}
   723  
   724  	vsv := &VirtualServerValidator{isPlus: false}
   725  
   726  	for _, test := range tests {
   727  		allErrs := vsv.validateVirtualServerRoutes(test.routes, field.NewPath("routes"), test.upstreamNames, "default")
   728  		if len(allErrs) == 0 {
   729  			t.Errorf("validateVirtualServerRoutes() returned no errors for the case of %s", test.msg)
   730  		}
   731  	}
   732  }
   733  
   734  func TestValidateRoute(t *testing.T) {
   735  	tests := []struct {
   736  		route                 v1.Route
   737  		upstreamNames         sets.String
   738  		isRouteFieldForbidden bool
   739  		msg                   string
   740  	}{
   741  		{
   742  			route: v1.Route{
   743  
   744  				Path: "/",
   745  				Action: &v1.Action{
   746  					Pass: "test",
   747  				},
   748  			},
   749  			upstreamNames: map[string]sets.Empty{
   750  				"test": {},
   751  			},
   752  			isRouteFieldForbidden: false,
   753  			msg:                   "valid route with upstream",
   754  		},
   755  		{
   756  			route: v1.Route{
   757  				Path: "/",
   758  				Splits: []v1.Split{
   759  					{
   760  						Weight: 90,
   761  						Action: &v1.Action{
   762  							Pass: "test-1",
   763  						},
   764  					},
   765  					{
   766  						Weight: 10,
   767  						Action: &v1.Action{
   768  							Pass: "test-2",
   769  						},
   770  					},
   771  				},
   772  			},
   773  			upstreamNames: map[string]sets.Empty{
   774  				"test-1": {},
   775  				"test-2": {},
   776  			},
   777  			isRouteFieldForbidden: false,
   778  			msg:                   "valid upstream with splits",
   779  		},
   780  		{
   781  			route: v1.Route{
   782  				Path: "/",
   783  				Matches: []v1.Match{
   784  					{
   785  						Conditions: []v1.Condition{
   786  							{
   787  								Header: "x-version",
   788  								Value:  "test-1",
   789  							},
   790  						},
   791  						Action: &v1.Action{
   792  							Pass: "test-1",
   793  						},
   794  					},
   795  				},
   796  				Action: &v1.Action{
   797  					Pass: "test-2",
   798  				},
   799  			},
   800  			upstreamNames: map[string]sets.Empty{
   801  				"test-1": {},
   802  				"test-2": {},
   803  			},
   804  			isRouteFieldForbidden: false,
   805  			msg:                   "valid action with matches",
   806  		},
   807  		{
   808  			route: v1.Route{
   809  
   810  				Path:  "/",
   811  				Route: "default/test",
   812  			},
   813  			upstreamNames:         map[string]sets.Empty{},
   814  			isRouteFieldForbidden: false,
   815  			msg:                   "valid route with route",
   816  		},
   817  	}
   818  
   819  	vsv := &VirtualServerValidator{isPlus: false}
   820  
   821  	for _, test := range tests {
   822  		allErrs := vsv.validateRoute(test.route, field.NewPath("route"), test.upstreamNames, test.isRouteFieldForbidden, "default")
   823  		if len(allErrs) > 0 {
   824  			t.Errorf("validateRoute() returned errors %v for valid input for the case of %s", allErrs, test.msg)
   825  		}
   826  	}
   827  }
   828  
   829  func TestValidateRouteFails(t *testing.T) {
   830  	tests := []struct {
   831  		route                 v1.Route
   832  		upstreamNames         sets.String
   833  		isRouteFieldForbidden bool
   834  		msg                   string
   835  	}{
   836  		{
   837  			route: v1.Route{
   838  				Path: "",
   839  				Action: &v1.Action{
   840  					Pass: "test",
   841  				},
   842  			},
   843  			upstreamNames: map[string]sets.Empty{
   844  				"test": {},
   845  			},
   846  			isRouteFieldForbidden: false,
   847  			msg:                   "empty path",
   848  		},
   849  		{
   850  			route: v1.Route{
   851  				Path: "/test",
   852  				Action: &v1.Action{
   853  					Pass: "-test",
   854  				},
   855  			},
   856  			upstreamNames:         sets.String{},
   857  			isRouteFieldForbidden: false,
   858  			msg:                   "invalid pass action",
   859  		},
   860  		{
   861  			route: v1.Route{
   862  				Path: "/",
   863  				Action: &v1.Action{
   864  					Pass: "test",
   865  				},
   866  			},
   867  			upstreamNames:         sets.String{},
   868  			isRouteFieldForbidden: false,
   869  			msg:                   "non-existing upstream in pass action",
   870  		},
   871  		{
   872  			route: v1.Route{
   873  				Path: "/",
   874  				Action: &v1.Action{
   875  					Pass: "test",
   876  				},
   877  				Splits: []v1.Split{
   878  					{
   879  						Weight: 90,
   880  						Action: &v1.Action{
   881  							Pass: "test-1",
   882  						},
   883  					},
   884  					{
   885  						Weight: 10,
   886  						Action: &v1.Action{
   887  							Pass: "test-2",
   888  						},
   889  					},
   890  				},
   891  			},
   892  			upstreamNames: map[string]sets.Empty{
   893  				"test":   {},
   894  				"test-1": {},
   895  				"test-2": {},
   896  			},
   897  			isRouteFieldForbidden: false,
   898  			msg:                   "both action and splits exist",
   899  		},
   900  		{
   901  			route: v1.Route{
   902  				Path: "/",
   903  				Splits: []v1.Split{
   904  					{
   905  						Weight: 90,
   906  						Action: &v1.Action{
   907  							Pass: "test-1",
   908  						},
   909  					},
   910  					{
   911  						Weight: 10,
   912  						Action: &v1.Action{
   913  							Pass: "test-2",
   914  						},
   915  					},
   916  				},
   917  				Matches: []v1.Match{
   918  					{
   919  						Conditions: []v1.Condition{
   920  							{
   921  								Header: "x-version",
   922  								Value:  "test-1",
   923  							},
   924  						},
   925  						Action: &v1.Action{
   926  							Pass: "test-1",
   927  						},
   928  					},
   929  				},
   930  				Action: &v1.Action{
   931  					Pass: "test-2",
   932  				},
   933  			},
   934  			upstreamNames: map[string]sets.Empty{
   935  				"test-1": {},
   936  				"test-2": {},
   937  			},
   938  			isRouteFieldForbidden: false,
   939  			msg:                   "both splits and matches exist",
   940  		},
   941  		{
   942  			route: v1.Route{
   943  				Path:  "/",
   944  				Route: "default/test",
   945  			},
   946  			upstreamNames:         map[string]sets.Empty{},
   947  			isRouteFieldForbidden: true,
   948  			msg:                   "route field exists but is forbidden",
   949  		},
   950  	}
   951  
   952  	vsv := &VirtualServerValidator{isPlus: false}
   953  
   954  	for _, test := range tests {
   955  		allErrs := vsv.validateRoute(test.route, field.NewPath("route"), test.upstreamNames, test.isRouteFieldForbidden, "default")
   956  		if len(allErrs) == 0 {
   957  			t.Errorf("validateRoute() returned no errors for invalid input for the case of %s", test.msg)
   958  		}
   959  	}
   960  }
   961  
   962  func TestValidateAction(t *testing.T) {
   963  	upstreamNames := map[string]sets.Empty{
   964  		"test": {},
   965  	}
   966  	tests := []struct {
   967  		action *v1.Action
   968  		msg    string
   969  	}{
   970  		{
   971  			action: &v1.Action{
   972  				Pass: "test",
   973  			},
   974  			msg: "base pass action",
   975  		},
   976  		{
   977  			action: &v1.Action{
   978  				Redirect: &v1.ActionRedirect{
   979  					URL: "http://www.nginx.com",
   980  				},
   981  			},
   982  			msg: "base redirect action",
   983  		},
   984  		{
   985  			action: &v1.Action{
   986  				Redirect: &v1.ActionRedirect{
   987  					URL:  "http://www.nginx.com",
   988  					Code: 302,
   989  				},
   990  			},
   991  			msg: "redirect action with status code set",
   992  		},
   993  		{
   994  			action: &v1.Action{
   995  				Proxy: &v1.ActionProxy{
   996  					Upstream:    "test",
   997  					RewritePath: "/rewrite",
   998  					RequestHeaders: &v1.ProxyRequestHeaders{
   999  						Set: []v1.Header{
  1000  							{
  1001  								Name:  "Header-Name",
  1002  								Value: "value",
  1003  							},
  1004  						},
  1005  					},
  1006  					ResponseHeaders: &v1.ProxyResponseHeaders{
  1007  						Hide:   []string{"header-name"},
  1008  						Pass:   []string{"header-name"},
  1009  						Ignore: []string{"Expires"},
  1010  						Add: []v1.AddHeader{
  1011  							{
  1012  								Header: v1.Header{
  1013  									Name:  "Header-Name",
  1014  									Value: "value",
  1015  								},
  1016  								Always: true,
  1017  							},
  1018  						},
  1019  					},
  1020  				},
  1021  			},
  1022  			msg: "proxy action with rewritePath, requestHeaders and responseHeaders",
  1023  		},
  1024  	}
  1025  
  1026  	vsv := &VirtualServerValidator{isPlus: false}
  1027  
  1028  	for _, test := range tests {
  1029  		allErrs := vsv.validateAction(test.action, field.NewPath("action"), upstreamNames, "", false)
  1030  		if len(allErrs) > 0 {
  1031  			t.Errorf("validateAction() returned errors %v for valid input for the case of %s", allErrs, test.msg)
  1032  		}
  1033  	}
  1034  }
  1035  
  1036  func TestValidateActionFails(t *testing.T) {
  1037  	upstreamNames := map[string]sets.Empty{}
  1038  
  1039  	tests := []struct {
  1040  		action *v1.Action
  1041  		msg    string
  1042  	}{
  1043  
  1044  		{
  1045  			action: &v1.Action{},
  1046  			msg:    "empty action",
  1047  		},
  1048  		{
  1049  			action: &v1.Action{
  1050  				Redirect: &v1.ActionRedirect{},
  1051  			},
  1052  			msg: "missing required field url",
  1053  		},
  1054  		{
  1055  			action: &v1.Action{
  1056  				Pass: "test",
  1057  				Redirect: &v1.ActionRedirect{
  1058  					URL: "http://www.nginx.com",
  1059  				},
  1060  			},
  1061  			msg: "multiple actions defined",
  1062  		},
  1063  		{
  1064  			action: &v1.Action{
  1065  				Redirect: &v1.ActionRedirect{
  1066  					URL:  "http://www.nginx.com",
  1067  					Code: 305,
  1068  				},
  1069  			},
  1070  			msg: "redirect action with invalid status code set",
  1071  		},
  1072  		{
  1073  			action: &v1.Action{
  1074  				Proxy: &v1.ActionProxy{
  1075  					Upstream: "",
  1076  				},
  1077  			},
  1078  			msg: "proxy action with missing upstream field",
  1079  		},
  1080  	}
  1081  
  1082  	vsv := &VirtualServerValidator{isPlus: false}
  1083  
  1084  	for _, test := range tests {
  1085  		allErrs := vsv.validateAction(test.action, field.NewPath("action"), upstreamNames, "", false)
  1086  		if len(allErrs) == 0 {
  1087  			t.Errorf("validateAction() returned no errors for invalid input for the case of %s", test.msg)
  1088  		}
  1089  	}
  1090  }
  1091  
  1092  func TestCaptureVariables(t *testing.T) {
  1093  	tests := []struct {
  1094  		s        string
  1095  		expected []string
  1096  	}{
  1097  		{
  1098  			"${scheme}://${host}",
  1099  			[]string{"scheme", "host"},
  1100  		},
  1101  		{
  1102  			"http://www.nginx.org",
  1103  			nil,
  1104  		},
  1105  		{
  1106  			"${}",
  1107  			[]string{""},
  1108  		},
  1109  	}
  1110  	for _, test := range tests {
  1111  		result := captureVariables(test.s)
  1112  		if !reflect.DeepEqual(result, test.expected) {
  1113  			t.Errorf("captureVariables(%s) returned %v but expected %v", test.s, result, test.expected)
  1114  		}
  1115  	}
  1116  }
  1117  
  1118  func TestValidateRedirectURL(t *testing.T) {
  1119  	tests := []struct {
  1120  		redirectURL string
  1121  		msg         string
  1122  	}{
  1123  		{
  1124  			redirectURL: "http://www.nginx.com",
  1125  			msg:         "base redirect url",
  1126  		},
  1127  		{
  1128  			redirectURL: "${scheme}://${host}/sorry",
  1129  			msg:         "multi variable redirect url",
  1130  		},
  1131  		{
  1132  			redirectURL: "${http_x_forwarded_proto}://${host}/sorry",
  1133  			msg:         "x-forwarded-proto redirect url use case",
  1134  		},
  1135  		{
  1136  			redirectURL: "http://${host}${request_uri}",
  1137  			msg:         "use multi variables, no scheme set",
  1138  		},
  1139  		{
  1140  			redirectURL: "${scheme}://www.${host}${request_uri}",
  1141  			msg:         "use multi variables",
  1142  		},
  1143  		{
  1144  			redirectURL: "http://example.com/redirect?source=abc",
  1145  			msg:         "arg variable use",
  1146  		},
  1147  		{
  1148  			redirectURL: `\"${scheme}://${host}\"`,
  1149  			msg:         "url with escaped quotes",
  1150  		},
  1151  		{
  1152  			redirectURL: "http://{abc}",
  1153  			msg:         "url with curly braces with no $ prefix",
  1154  		},
  1155  	}
  1156  
  1157  	vsv := &VirtualServerValidator{isPlus: false}
  1158  
  1159  	for _, test := range tests {
  1160  		allErrs := vsv.validateRedirectURL(test.redirectURL, field.NewPath("url"), validRedirectVariableNames)
  1161  		if len(allErrs) > 0 {
  1162  			t.Errorf("validateRedirectURL(%s) returned errors %v for valid input for the case of %s", test.redirectURL, allErrs, test.msg)
  1163  		}
  1164  	}
  1165  }
  1166  
  1167  func TestValidateRedirectURLFails(t *testing.T) {
  1168  	tests := []struct {
  1169  		redirectURL string
  1170  		msg         string
  1171  	}{
  1172  
  1173  		{
  1174  			redirectURL: "",
  1175  			msg:         "url is blank",
  1176  		},
  1177  		{
  1178  			redirectURL: "/uri",
  1179  			msg:         "url does not start with http://, https:// or ${scheme}://",
  1180  		},
  1181  		{
  1182  			redirectURL: "$scheme://www.$host.com",
  1183  			msg:         "usage of nginx variable in url without ${}",
  1184  		},
  1185  		{
  1186  			redirectURL: "${scheme}://www.${invalid}.com",
  1187  			msg:         "invalid nginx variable in url",
  1188  		},
  1189  		{
  1190  			redirectURL: "${scheme}://www.${{host}.com",
  1191  			msg:         "leading curly brace",
  1192  		},
  1193  		{
  1194  			redirectURL: "${host.abc}.com",
  1195  			msg:         "multi var in curly brace",
  1196  		},
  1197  		{
  1198  			redirectURL: "${scheme}://www.${host{host}}.com",
  1199  			msg:         "nested nginx vars",
  1200  		},
  1201  		{
  1202  			redirectURL: `"${scheme}://${host}"`,
  1203  			msg:         "url in unescaped quotes",
  1204  		},
  1205  		{
  1206  			redirectURL: `"${scheme}://${host}`,
  1207  			msg:         "url with unescaped quote prefix",
  1208  		},
  1209  		{
  1210  			redirectURL: `\\"${scheme}://${host}\\"`,
  1211  			msg:         "url with escaped backslash",
  1212  		},
  1213  		{
  1214  			redirectURL: `${scheme}://${host}$`,
  1215  			msg:         "url with ending $",
  1216  		},
  1217  		{
  1218  			redirectURL: `http://${}`,
  1219  			msg:         "url containing blank var",
  1220  		},
  1221  		{
  1222  			redirectURL: `http://${abca`,
  1223  			msg:         "url containing a var without ending }",
  1224  		},
  1225  	}
  1226  
  1227  	vsv := &VirtualServerValidator{isPlus: false}
  1228  
  1229  	for _, test := range tests {
  1230  		allErrs := vsv.validateRedirectURL(test.redirectURL, field.NewPath("action"), validRedirectVariableNames)
  1231  		if len(allErrs) == 0 {
  1232  			t.Errorf("validateRedirectURL(%s) returned no errors for invalid input for the case of %s", test.redirectURL, test.msg)
  1233  		}
  1234  	}
  1235  }
  1236  
  1237  func TestValidateRouteField(t *testing.T) {
  1238  	validRouteFields := []string{
  1239  		"coffee",
  1240  		"default/coffee",
  1241  	}
  1242  
  1243  	for _, rf := range validRouteFields {
  1244  		allErrs := validateRouteField(rf, field.NewPath("route"))
  1245  		if len(allErrs) > 0 {
  1246  			t.Errorf("validRouteField(%q) returned errors %v for valid input", rf, allErrs)
  1247  		}
  1248  	}
  1249  
  1250  	invalidRouteFields := []string{
  1251  		"-",
  1252  		"/coffee",
  1253  		"-/coffee",
  1254  	}
  1255  
  1256  	for _, rf := range invalidRouteFields {
  1257  		allErrs := validateRouteField(rf, field.NewPath("route"))
  1258  		if len(allErrs) == 0 {
  1259  			t.Errorf("validRouteField(%q) returned no errors for invalid input", rf)
  1260  		}
  1261  	}
  1262  }
  1263  
  1264  func TestValdateReferencedUpstream(t *testing.T) {
  1265  	upstream := "test"
  1266  	upstreamNames := map[string]sets.Empty{
  1267  		"test": {},
  1268  	}
  1269  
  1270  	allErrs := validateReferencedUpstream(upstream, field.NewPath("upstream"), upstreamNames)
  1271  	if len(allErrs) > 0 {
  1272  		t.Errorf("validateReferencedUpstream() returned errors %v for valid input", allErrs)
  1273  	}
  1274  }
  1275  
  1276  func TestValdateUpstreamFails(t *testing.T) {
  1277  	tests := []struct {
  1278  		upstream      string
  1279  		upstreamNames sets.String
  1280  		msg           string
  1281  	}{
  1282  		{
  1283  			upstream:      "",
  1284  			upstreamNames: map[string]sets.Empty{},
  1285  			msg:           "empty upstream",
  1286  		},
  1287  		{
  1288  			upstream:      "-test",
  1289  			upstreamNames: map[string]sets.Empty{},
  1290  			msg:           "invalid upstream",
  1291  		},
  1292  		{
  1293  			upstream:      "test",
  1294  			upstreamNames: map[string]sets.Empty{},
  1295  			msg:           "non-existing upstream",
  1296  		},
  1297  	}
  1298  
  1299  	for _, test := range tests {
  1300  		allErrs := validateReferencedUpstream(test.upstream, field.NewPath("upstream"), test.upstreamNames)
  1301  		if len(allErrs) == 0 {
  1302  			t.Errorf("validateReferencedUpstream() returned no errors for invalid input for the case of %s", test.msg)
  1303  		}
  1304  	}
  1305  }
  1306  
  1307  func TestValidateRegexPath(t *testing.T) {
  1308  	tests := []struct {
  1309  		regexPath string
  1310  		msg       string
  1311  	}{
  1312  		{
  1313  			regexPath: "~ ^/foo.*\\.jpg",
  1314  			msg:       "case sensitive regexp",
  1315  		},
  1316  		{
  1317  			regexPath: "~* ^/Bar.*\\.jpg",
  1318  			msg:       "case insensitive regexp",
  1319  		},
  1320  		{
  1321  			regexPath: `~ ^/f\"oo.*\\.jpg`,
  1322  			msg:       "regexp with escaped double quotes",
  1323  		},
  1324  	}
  1325  
  1326  	for _, test := range tests {
  1327  		allErrs := validateRegexPath(test.regexPath, field.NewPath("path"))
  1328  		if len(allErrs) != 0 {
  1329  			t.Errorf("validateRegexPath(%v) returned errors for valid input for the case of %v", test.regexPath, test.msg)
  1330  		}
  1331  	}
  1332  }
  1333  
  1334  func TestValidateRegexPathFails(t *testing.T) {
  1335  	tests := []struct {
  1336  		regexPath string
  1337  		msg       string
  1338  	}{
  1339  		{
  1340  			regexPath: "~ [{",
  1341  			msg:       "invalid regexp",
  1342  		},
  1343  		{
  1344  			regexPath: `~ /foo"`,
  1345  			msg:       "unescaped double quotes",
  1346  		},
  1347  		{
  1348  			regexPath: `~"`,
  1349  			msg:       "empty regex",
  1350  		},
  1351  		{
  1352  			regexPath: `~ /foo\`,
  1353  			msg:       "ending in backslash",
  1354  		},
  1355  	}
  1356  
  1357  	for _, test := range tests {
  1358  		allErrs := validateRegexPath(test.regexPath, field.NewPath("path"))
  1359  		if len(allErrs) == 0 {
  1360  			t.Errorf("validateRegexPath(%v) returned no errors for invalid input for the case of %v", test.regexPath, test.msg)
  1361  		}
  1362  	}
  1363  }
  1364  
  1365  func TestValidateRoutePath(t *testing.T) {
  1366  	validPaths := []string{
  1367  		"/",
  1368  		"~ /^foo.*\\.jpg",
  1369  		"~* /^Bar.*\\.jpg",
  1370  		"=/exact/match",
  1371  	}
  1372  
  1373  	for _, path := range validPaths {
  1374  		allErrs := validateRoutePath(path, field.NewPath("path"))
  1375  		if len(allErrs) != 0 {
  1376  			t.Errorf("validateRoutePath(%v) returned errors for valid input", path)
  1377  		}
  1378  	}
  1379  
  1380  	invalidPaths := []string{
  1381  		"",
  1382  		"invalid",
  1383  	}
  1384  
  1385  	for _, path := range invalidPaths {
  1386  		allErrs := validateRoutePath(path, field.NewPath("path"))
  1387  		if len(allErrs) == 0 {
  1388  			t.Errorf("validateRoutePath(%v) returned no errors for invalid input", path)
  1389  		}
  1390  	}
  1391  }
  1392  
  1393  func TestValidatePath(t *testing.T) {
  1394  	validPaths := []string{
  1395  		"/",
  1396  		"/path",
  1397  		"/a-1/_A/",
  1398  	}
  1399  
  1400  	for _, path := range validPaths {
  1401  		allErrs := validatePath(path, field.NewPath("path"))
  1402  		if len(allErrs) > 0 {
  1403  			t.Errorf("validatePath(%q) returned errors %v for valid input", path, allErrs)
  1404  		}
  1405  	}
  1406  
  1407  	invalidPaths := []string{
  1408  		"",
  1409  		" /",
  1410  		"/ ",
  1411  		"/{",
  1412  		"/}",
  1413  		"/abc;",
  1414  	}
  1415  
  1416  	for _, path := range invalidPaths {
  1417  		allErrs := validatePath(path, field.NewPath("path"))
  1418  		if len(allErrs) == 0 {
  1419  			t.Errorf("validatePath(%q) returned no errors for invalid input", path)
  1420  		}
  1421  	}
  1422  }
  1423  
  1424  func TestValidateSplits(t *testing.T) {
  1425  	splits := []v1.Split{
  1426  		{
  1427  			Weight: 90,
  1428  			Action: &v1.Action{
  1429  				Pass: "test-1",
  1430  			},
  1431  		},
  1432  		{
  1433  			Weight: 10,
  1434  			Action: &v1.Action{
  1435  				Proxy: &v1.ActionProxy{
  1436  					Upstream: "test-2",
  1437  				},
  1438  			},
  1439  		},
  1440  	}
  1441  	upstreamNames := map[string]sets.Empty{
  1442  		"test-1": {},
  1443  		"test-2": {},
  1444  	}
  1445  
  1446  	vsv := &VirtualServerValidator{isPlus: false}
  1447  
  1448  	allErrs := vsv.validateSplits(splits, field.NewPath("splits"), upstreamNames, "")
  1449  	if len(allErrs) > 0 {
  1450  		t.Errorf("validateSplits() returned errors %v for valid input", allErrs)
  1451  	}
  1452  }
  1453  
  1454  func TestValidateSplitsFails(t *testing.T) {
  1455  	tests := []struct {
  1456  		splits        []v1.Split
  1457  		upstreamNames sets.String
  1458  		msg           string
  1459  	}{
  1460  		{
  1461  			splits: []v1.Split{
  1462  				{
  1463  					Weight: 90,
  1464  					Action: &v1.Action{
  1465  						Pass: "test-1",
  1466  					},
  1467  				},
  1468  			},
  1469  			upstreamNames: map[string]sets.Empty{
  1470  				"test-1": {},
  1471  			},
  1472  			msg: "only one split",
  1473  		},
  1474  		{
  1475  			splits: []v1.Split{
  1476  				{
  1477  					Weight: 123,
  1478  					Action: &v1.Action{
  1479  						Pass: "test-1",
  1480  					},
  1481  				},
  1482  				{
  1483  					Weight: 10,
  1484  					Action: &v1.Action{
  1485  						Pass: "test-2",
  1486  					},
  1487  				},
  1488  			},
  1489  			upstreamNames: map[string]sets.Empty{
  1490  				"test-1": {},
  1491  				"test-2": {},
  1492  			},
  1493  			msg: "invalid weight",
  1494  		},
  1495  		{
  1496  			splits: []v1.Split{
  1497  				{
  1498  					Weight: 99,
  1499  					Action: &v1.Action{
  1500  						Pass: "test-1",
  1501  					},
  1502  				},
  1503  				{
  1504  					Weight: 99,
  1505  					Action: &v1.Action{
  1506  						Pass: "test-2",
  1507  					},
  1508  				},
  1509  			},
  1510  			upstreamNames: map[string]sets.Empty{
  1511  				"test-1": {},
  1512  				"test-2": {},
  1513  			},
  1514  			msg: "invalid total weight",
  1515  		},
  1516  		{
  1517  			splits: []v1.Split{
  1518  				{
  1519  					Weight: 90,
  1520  					Action: &v1.Action{
  1521  						Pass: "",
  1522  					},
  1523  				},
  1524  				{
  1525  					Weight: 10,
  1526  					Action: &v1.Action{
  1527  						Pass: "test-2",
  1528  					},
  1529  				},
  1530  			},
  1531  			upstreamNames: map[string]sets.Empty{
  1532  				"test-1": {},
  1533  				"test-2": {},
  1534  			},
  1535  			msg: "invalid action",
  1536  		},
  1537  		{
  1538  			splits: []v1.Split{
  1539  				{
  1540  					Weight: 90,
  1541  					Action: &v1.Action{
  1542  						Pass: "some-upstream",
  1543  					},
  1544  				},
  1545  				{
  1546  					Weight: 10,
  1547  					Action: &v1.Action{
  1548  						Pass: "test-2",
  1549  					},
  1550  				},
  1551  			},
  1552  			upstreamNames: map[string]sets.Empty{
  1553  				"test-1": {},
  1554  				"test-2": {},
  1555  			},
  1556  			msg: "invalid action with non-existing upstream",
  1557  		},
  1558  	}
  1559  
  1560  	vsv := &VirtualServerValidator{isPlus: false}
  1561  
  1562  	for _, test := range tests {
  1563  		allErrs := vsv.validateSplits(test.splits, field.NewPath("splits"), test.upstreamNames, "")
  1564  		if len(allErrs) == 0 {
  1565  			t.Errorf("validateSplits() returned no errors for invalid input for the case of %s", test.msg)
  1566  		}
  1567  	}
  1568  }
  1569  
  1570  func TestValidateCondition(t *testing.T) {
  1571  	tests := []struct {
  1572  		condition v1.Condition
  1573  		msg       string
  1574  	}{
  1575  		{
  1576  			condition: v1.Condition{
  1577  				Header: "x-version",
  1578  				Value:  "v1",
  1579  			},
  1580  			msg: "valid header",
  1581  		},
  1582  		{
  1583  			condition: v1.Condition{
  1584  				Cookie: "my_cookie",
  1585  				Value:  "",
  1586  			},
  1587  			msg: "valid cookie",
  1588  		},
  1589  		{
  1590  			condition: v1.Condition{
  1591  				Argument: "arg",
  1592  				Value:    "yes",
  1593  			},
  1594  			msg: "valid argument",
  1595  		},
  1596  		{
  1597  			condition: v1.Condition{
  1598  				Variable: "$request_method",
  1599  				Value:    "POST",
  1600  			},
  1601  			msg: "valid variable",
  1602  		},
  1603  	}
  1604  
  1605  	for _, test := range tests {
  1606  		allErrs := validateCondition(test.condition, field.NewPath("condition"))
  1607  		if len(allErrs) > 0 {
  1608  			t.Errorf("validateCondition() returned errors %v for valid input for the case of %s", allErrs, test.msg)
  1609  		}
  1610  	}
  1611  }
  1612  
  1613  func TestValidateConditionFails(t *testing.T) {
  1614  	tests := []struct {
  1615  		condition v1.Condition
  1616  		msg       string
  1617  	}{
  1618  		{
  1619  			condition: v1.Condition{},
  1620  			msg:       "empty condition",
  1621  		},
  1622  		{
  1623  			condition: v1.Condition{
  1624  				Header:   "x-version",
  1625  				Cookie:   "user",
  1626  				Argument: "answer",
  1627  				Variable: "$request_method",
  1628  				Value:    "something",
  1629  			},
  1630  			msg: "invalid condition",
  1631  		},
  1632  		{
  1633  			condition: v1.Condition{
  1634  				Header: "x_version",
  1635  			},
  1636  			msg: "invalid header",
  1637  		},
  1638  		{
  1639  			condition: v1.Condition{
  1640  				Cookie: "my-cookie",
  1641  			},
  1642  			msg: "invalid cookie",
  1643  		},
  1644  		{
  1645  			condition: v1.Condition{
  1646  				Argument: "my-arg",
  1647  			},
  1648  			msg: "invalid argument",
  1649  		},
  1650  		{
  1651  			condition: v1.Condition{
  1652  				Variable: "request_method",
  1653  			},
  1654  			msg: "invalid variable",
  1655  		},
  1656  	}
  1657  
  1658  	for _, test := range tests {
  1659  		allErrs := validateCondition(test.condition, field.NewPath("condition"))
  1660  		if len(allErrs) == 0 {
  1661  			t.Errorf("validateCondition() returned no errors for invalid input for the case of %s", test.msg)
  1662  		}
  1663  	}
  1664  }
  1665  
  1666  func TestIsCookieName(t *testing.T) {
  1667  	validCookieNames := []string{
  1668  		"123",
  1669  		"my_cookie",
  1670  	}
  1671  
  1672  	for _, name := range validCookieNames {
  1673  		errs := isCookieName(name)
  1674  		if len(errs) > 0 {
  1675  			t.Errorf("isCookieName(%q) returned errors %v for valid input", name, errs)
  1676  		}
  1677  	}
  1678  
  1679  	invalidCookieNames := []string{
  1680  		"",
  1681  		"my-cookie",
  1682  		"cookie!",
  1683  	}
  1684  
  1685  	for _, name := range invalidCookieNames {
  1686  		errs := isCookieName(name)
  1687  		if len(errs) == 0 {
  1688  			t.Errorf("isCookieName(%q) returned no errors for invalid input", name)
  1689  		}
  1690  	}
  1691  }
  1692  
  1693  func TestIsArgumentName(t *testing.T) {
  1694  	validArgumentNames := []string{
  1695  		"123",
  1696  		"my_arg",
  1697  	}
  1698  
  1699  	for _, name := range validArgumentNames {
  1700  		errs := isArgumentName(name)
  1701  		if len(errs) > 0 {
  1702  			t.Errorf("isArgumentName(%q) returned errors %v for valid input", name, errs)
  1703  		}
  1704  	}
  1705  
  1706  	invalidArgumentNames := []string{
  1707  		"",
  1708  		"my-arg",
  1709  		"arg!",
  1710  	}
  1711  
  1712  	for _, name := range invalidArgumentNames {
  1713  		errs := isArgumentName(name)
  1714  		if len(errs) == 0 {
  1715  			t.Errorf("isArgumentName(%q) returned no errors for invalid input", name)
  1716  		}
  1717  	}
  1718  }
  1719  
  1720  func TestValidateVariableName(t *testing.T) {
  1721  	validNames := []string{
  1722  		"$request_method",
  1723  	}
  1724  
  1725  	for _, name := range validNames {
  1726  		allErrs := validateVariableName(name, field.NewPath("variable"))
  1727  		if len(allErrs) > 0 {
  1728  			t.Errorf("validateVariableName(%q) returned errors %v for valid input", name, allErrs)
  1729  		}
  1730  	}
  1731  
  1732  	invalidNames := []string{
  1733  		"request_method",
  1734  		"$request_id",
  1735  	}
  1736  
  1737  	for _, name := range invalidNames {
  1738  		allErrs := validateVariableName(name, field.NewPath("variable"))
  1739  		if len(allErrs) == 0 {
  1740  			t.Errorf("validateVariableName(%q) returned no errors for invalid input", name)
  1741  		}
  1742  	}
  1743  }
  1744  
  1745  func TestValidateMatch(t *testing.T) {
  1746  	tests := []struct {
  1747  		match         v1.Match
  1748  		upstreamNames sets.String
  1749  		msg           string
  1750  	}{
  1751  		{
  1752  			match: v1.Match{
  1753  				Conditions: []v1.Condition{
  1754  					{
  1755  						Cookie: "version",
  1756  						Value:  "v1",
  1757  					},
  1758  				},
  1759  				Action: &v1.Action{
  1760  					Pass: "test",
  1761  				},
  1762  			},
  1763  			upstreamNames: map[string]sets.Empty{
  1764  				"test": {},
  1765  			},
  1766  			msg: "valid match with action",
  1767  		},
  1768  		{
  1769  			match: v1.Match{
  1770  				Conditions: []v1.Condition{
  1771  					{
  1772  						Cookie: "version",
  1773  						Value:  "v1",
  1774  					},
  1775  				},
  1776  				Splits: []v1.Split{
  1777  					{
  1778  						Weight: 90,
  1779  						Action: &v1.Action{
  1780  							Pass: "test-1",
  1781  						},
  1782  					},
  1783  					{
  1784  						Weight: 10,
  1785  						Action: &v1.Action{
  1786  							Pass: "test-2",
  1787  						},
  1788  					},
  1789  				},
  1790  			},
  1791  			upstreamNames: map[string]sets.Empty{
  1792  				"test-1": {},
  1793  				"test-2": {},
  1794  			},
  1795  			msg: "valid match with splits",
  1796  		},
  1797  	}
  1798  
  1799  	vsv := &VirtualServerValidator{isPlus: false}
  1800  
  1801  	for _, test := range tests {
  1802  		allErrs := vsv.validateMatch(test.match, field.NewPath("match"), test.upstreamNames, "")
  1803  		if len(allErrs) > 0 {
  1804  			t.Errorf("validateMatch() returned errors %v for valid input for the case of %s", allErrs, test.msg)
  1805  		}
  1806  	}
  1807  }
  1808  
  1809  func TestValidateMatchFails(t *testing.T) {
  1810  	tests := []struct {
  1811  		match         v1.Match
  1812  		upstreamNames sets.String
  1813  		msg           string
  1814  	}{
  1815  		{
  1816  			match: v1.Match{
  1817  				Conditions: []v1.Condition{},
  1818  				Action: &v1.Action{
  1819  					Pass: "test",
  1820  				},
  1821  			},
  1822  			upstreamNames: map[string]sets.Empty{
  1823  				"test": {},
  1824  			},
  1825  			msg: "invalid number of conditions",
  1826  		},
  1827  		{
  1828  			match: v1.Match{
  1829  				Conditions: []v1.Condition{
  1830  					{
  1831  						Cookie: "version",
  1832  						Value:  `v1"`,
  1833  					},
  1834  				},
  1835  				Action: &v1.Action{
  1836  					Pass: "test",
  1837  				},
  1838  			},
  1839  			upstreamNames: map[string]sets.Empty{
  1840  				"test": {},
  1841  			},
  1842  			msg: "invalid condition",
  1843  		},
  1844  		{
  1845  			match: v1.Match{
  1846  				Conditions: []v1.Condition{
  1847  					{
  1848  						Cookie: "version",
  1849  						Value:  "v1",
  1850  					},
  1851  				},
  1852  				Action: &v1.Action{},
  1853  			},
  1854  			upstreamNames: map[string]sets.Empty{},
  1855  			msg:           "invalid  action",
  1856  		},
  1857  		{
  1858  			match: v1.Match{
  1859  				Conditions: []v1.Condition{
  1860  					{
  1861  						Cookie: "version",
  1862  						Value:  "v1",
  1863  					},
  1864  				},
  1865  				Action: &v1.Action{
  1866  					Pass: "test-1",
  1867  				},
  1868  				Splits: []v1.Split{
  1869  					{
  1870  						Weight: 90,
  1871  						Action: &v1.Action{
  1872  							Pass: "test-1",
  1873  						},
  1874  					},
  1875  					{
  1876  						Weight: 10,
  1877  						Action: &v1.Action{
  1878  							Pass: "test-2",
  1879  						},
  1880  					},
  1881  				},
  1882  			},
  1883  			upstreamNames: map[string]sets.Empty{
  1884  				"test-1": {},
  1885  				"test-2": {},
  1886  			},
  1887  			msg: "both splits and action are set",
  1888  		},
  1889  	}
  1890  
  1891  	vsv := &VirtualServerValidator{isPlus: false}
  1892  
  1893  	for _, test := range tests {
  1894  		allErrs := vsv.validateMatch(test.match, field.NewPath("match"), test.upstreamNames, "")
  1895  		if len(allErrs) == 0 {
  1896  			t.Errorf("validateMatch() returned no errors for invalid input for the case of %s", test.msg)
  1897  		}
  1898  	}
  1899  }
  1900  
  1901  func TestIsValidMatchValue(t *testing.T) {
  1902  	validValues := []string{
  1903  		"abc",
  1904  		"123",
  1905  		`\"
  1906  		abc\"`,
  1907  		`\"`,
  1908  	}
  1909  
  1910  	for _, value := range validValues {
  1911  		errs := isValidMatchValue(value)
  1912  		if len(errs) > 0 {
  1913  			t.Errorf("isValidMatchValue(%q) returned errors %v for valid input", value, errs)
  1914  		}
  1915  	}
  1916  
  1917  	invalidValues := []string{
  1918  		`"`,
  1919  		`\`,
  1920  		`abc"`,
  1921  		`abc\\\`,
  1922  		`a"b`,
  1923  	}
  1924  
  1925  	for _, value := range invalidValues {
  1926  		errs := isValidMatchValue(value)
  1927  		if len(errs) == 0 {
  1928  			t.Errorf("isValidMatchValue(%q) returned no errors for invalid input", value)
  1929  		}
  1930  	}
  1931  }
  1932  
  1933  func TestValidateVirtualServerRoute(t *testing.T) {
  1934  	virtualServerRoute := v1.VirtualServerRoute{
  1935  		ObjectMeta: meta_v1.ObjectMeta{
  1936  			Name:      "coffee",
  1937  			Namespace: "default",
  1938  		},
  1939  		Spec: v1.VirtualServerRouteSpec{
  1940  			Host: "example.com",
  1941  			Upstreams: []v1.Upstream{
  1942  				{
  1943  					Name:    "first",
  1944  					Service: "service-1",
  1945  					Port:    80,
  1946  				},
  1947  				{
  1948  					Name:    "second",
  1949  					Service: "service-2",
  1950  					Port:    80,
  1951  				},
  1952  			},
  1953  			Subroutes: []v1.Route{
  1954  				{
  1955  					Path: "/test/first",
  1956  					Action: &v1.Action{
  1957  						Pass: "first",
  1958  					},
  1959  				},
  1960  				{
  1961  					Path: "/test/second",
  1962  					Action: &v1.Action{
  1963  						Pass: "second",
  1964  					},
  1965  				},
  1966  			},
  1967  		},
  1968  	}
  1969  
  1970  	vsv := &VirtualServerValidator{isPlus: false}
  1971  
  1972  	err := vsv.ValidateVirtualServerRoute(&virtualServerRoute)
  1973  	if err != nil {
  1974  		t.Errorf("ValidateVirtualServerRoute() returned error %v for valid input %v", err, virtualServerRoute)
  1975  	}
  1976  }
  1977  
  1978  func TestValidateVirtualServerRouteForVirtualServer(t *testing.T) {
  1979  	virtualServerRoute := v1.VirtualServerRoute{
  1980  		ObjectMeta: meta_v1.ObjectMeta{
  1981  			Name:      "coffee",
  1982  			Namespace: "default",
  1983  		},
  1984  		Spec: v1.VirtualServerRouteSpec{
  1985  			Host: "example.com",
  1986  			Upstreams: []v1.Upstream{
  1987  				{
  1988  					Name:    "first",
  1989  					Service: "service-1",
  1990  					Port:    80,
  1991  				},
  1992  				{
  1993  					Name:    "second",
  1994  					Service: "service-2",
  1995  					Port:    80,
  1996  				},
  1997  			},
  1998  			Subroutes: []v1.Route{
  1999  				{
  2000  					Path: "/test/first",
  2001  					Action: &v1.Action{
  2002  						Pass: "first",
  2003  					},
  2004  				},
  2005  				{
  2006  					Path: "/test/second",
  2007  					Action: &v1.Action{
  2008  						Pass: "second",
  2009  					},
  2010  				},
  2011  			},
  2012  		},
  2013  	}
  2014  	virtualServerHost := "example.com"
  2015  	pathPrefix := "/test"
  2016  
  2017  	vsv := &VirtualServerValidator{isPlus: false}
  2018  
  2019  	err := vsv.ValidateVirtualServerRouteForVirtualServer(&virtualServerRoute, virtualServerHost, pathPrefix)
  2020  	if err != nil {
  2021  		t.Errorf("ValidateVirtualServerRouteForVirtualServer() returned error %v for valid input %v", err, virtualServerRoute)
  2022  	}
  2023  }
  2024  
  2025  func TestValidateVirtualServerRouteHost(t *testing.T) {
  2026  	virtualServerHost := "example.com"
  2027  
  2028  	validHost := "example.com"
  2029  
  2030  	allErrs := validateVirtualServerRouteHost(validHost, virtualServerHost, field.NewPath("host"))
  2031  	if len(allErrs) > 0 {
  2032  		t.Errorf("validateVirtualServerRouteHost() returned errors %v for valid input", allErrs)
  2033  	}
  2034  
  2035  	invalidHost := "foo.example.com"
  2036  
  2037  	allErrs = validateVirtualServerRouteHost(invalidHost, virtualServerHost, field.NewPath("host"))
  2038  	if len(allErrs) == 0 {
  2039  		t.Errorf("validateVirtualServerRouteHost() returned no errors for invalid input")
  2040  	}
  2041  }
  2042  
  2043  func TestValidateVirtualServerRouteSubroutes(t *testing.T) {
  2044  	tests := []struct {
  2045  		routes        []v1.Route
  2046  		upstreamNames sets.String
  2047  		pathPrefix    string
  2048  		msg           string
  2049  	}{
  2050  		{
  2051  			routes:        []v1.Route{},
  2052  			upstreamNames: sets.String{},
  2053  			pathPrefix:    "/",
  2054  			msg:           "no routes",
  2055  		},
  2056  		{
  2057  			routes: []v1.Route{
  2058  				{
  2059  					Path: "/",
  2060  					Action: &v1.Action{
  2061  						Pass: "test",
  2062  					},
  2063  				},
  2064  			},
  2065  			upstreamNames: map[string]sets.Empty{
  2066  				"test": {},
  2067  			},
  2068  			pathPrefix: "/",
  2069  			msg:        "valid route",
  2070  		},
  2071  	}
  2072  
  2073  	vsv := &VirtualServerValidator{isPlus: false}
  2074  
  2075  	for _, test := range tests {
  2076  		allErrs := vsv.validateVirtualServerRouteSubroutes(test.routes, field.NewPath("subroutes"), test.upstreamNames,
  2077  			test.pathPrefix, "default")
  2078  		if len(allErrs) > 0 {
  2079  			t.Errorf("validateVirtualServerRouteSubroutes() returned errors %v for valid input for the case of %s", allErrs, test.msg)
  2080  		}
  2081  	}
  2082  }
  2083  
  2084  func TestValidateVirtualServerRouteSubroutesFails(t *testing.T) {
  2085  	tests := []struct {
  2086  		routes        []v1.Route
  2087  		upstreamNames sets.String
  2088  		pathPrefix    string
  2089  		msg           string
  2090  	}{
  2091  		{
  2092  			routes: []v1.Route{
  2093  				{
  2094  					Path: "/test",
  2095  					Action: &v1.Action{
  2096  						Pass: "test-1",
  2097  					},
  2098  				},
  2099  				{
  2100  					Path: "/test",
  2101  					Action: &v1.Action{
  2102  						Pass: "test-2",
  2103  					},
  2104  				},
  2105  			},
  2106  			upstreamNames: map[string]sets.Empty{
  2107  				"test-1": {},
  2108  				"test-2": {},
  2109  			},
  2110  			pathPrefix: "/",
  2111  			msg:        "duplicated paths",
  2112  		},
  2113  		{
  2114  			routes: []v1.Route{
  2115  				{
  2116  					Path:   "",
  2117  					Action: nil,
  2118  				},
  2119  			},
  2120  			upstreamNames: map[string]sets.Empty{},
  2121  			pathPrefix:    "",
  2122  			msg:           "invalid route",
  2123  		},
  2124  		{
  2125  			routes: []v1.Route{
  2126  				{
  2127  					Path: "/",
  2128  					Action: &v1.Action{
  2129  						Pass: "test-1",
  2130  					},
  2131  				},
  2132  			},
  2133  			upstreamNames: map[string]sets.Empty{
  2134  				"test-1": {},
  2135  			},
  2136  			pathPrefix: "/abc",
  2137  			msg:        "invalid prefix",
  2138  		},
  2139  	}
  2140  
  2141  	vsv := &VirtualServerValidator{isPlus: false}
  2142  
  2143  	for _, test := range tests {
  2144  		allErrs := vsv.validateVirtualServerRouteSubroutes(test.routes, field.NewPath("subroutes"), test.upstreamNames,
  2145  			test.pathPrefix, "default")
  2146  		if len(allErrs) == 0 {
  2147  			t.Errorf("validateVirtualServerRouteSubroutes() returned no errors for the case of %s", test.msg)
  2148  		}
  2149  	}
  2150  }
  2151  
  2152  func TestValidateUpstreamLBMethod(t *testing.T) {
  2153  	tests := []struct {
  2154  		method string
  2155  		isPlus bool
  2156  	}{
  2157  		{
  2158  			method: "round_robin",
  2159  			isPlus: false,
  2160  		},
  2161  		{
  2162  			method: "",
  2163  			isPlus: false,
  2164  		},
  2165  		{
  2166  			method: "ip_hash",
  2167  			isPlus: true,
  2168  		},
  2169  		{
  2170  			method: "",
  2171  			isPlus: true,
  2172  		},
  2173  	}
  2174  
  2175  	for _, test := range tests {
  2176  		allErrs := validateUpstreamLBMethod(test.method, field.NewPath("lb-method"), test.isPlus)
  2177  
  2178  		if len(allErrs) != 0 {
  2179  			t.Errorf("validateUpstreamLBMethod(%q, %v) returned errors for method %s", test.method, test.isPlus, test.method)
  2180  		}
  2181  	}
  2182  }
  2183  
  2184  func TestValidateUpstreamLBMethodFails(t *testing.T) {
  2185  	tests := []struct {
  2186  		method string
  2187  		isPlus bool
  2188  	}{
  2189  		{
  2190  			method: "wrong",
  2191  			isPlus: false,
  2192  		},
  2193  		{
  2194  			method: "wrong",
  2195  			isPlus: true,
  2196  		},
  2197  	}
  2198  
  2199  	for _, test := range tests {
  2200  		allErrs := validateUpstreamLBMethod(test.method, field.NewPath("lb-method"), test.isPlus)
  2201  
  2202  		if len(allErrs) == 0 {
  2203  			t.Errorf("validateUpstreamLBMethod(%q, %v) returned no errors for method %s", test.method, test.isPlus, test.method)
  2204  		}
  2205  	}
  2206  }
  2207  
  2208  func TestValidatePositiveIntOrZeroFromPointer(t *testing.T) {
  2209  	tests := []struct {
  2210  		number *int
  2211  		msg    string
  2212  	}{
  2213  		{
  2214  			number: nil,
  2215  			msg:    "valid (nil)",
  2216  		},
  2217  		{
  2218  			number: createPointerFromInt(0),
  2219  			msg:    "valid (0)",
  2220  		},
  2221  		{
  2222  			number: createPointerFromInt(1),
  2223  			msg:    "valid (1)",
  2224  		},
  2225  	}
  2226  
  2227  	for _, test := range tests {
  2228  		allErrs := validatePositiveIntOrZeroFromPointer(test.number, field.NewPath("int-field"))
  2229  
  2230  		if len(allErrs) != 0 {
  2231  			t.Errorf("validatePositiveIntOrZeroFromPointer returned errors for case: %v", test.msg)
  2232  		}
  2233  	}
  2234  }
  2235  
  2236  func TestValidatePositiveIntOrZeroFromPointerFails(t *testing.T) {
  2237  	number := createPointerFromInt(-1)
  2238  	allErrs := validatePositiveIntOrZeroFromPointer(number, field.NewPath("int-field"))
  2239  
  2240  	if len(allErrs) == 0 {
  2241  		t.Error("validatePositiveIntOrZeroFromPointer returned no errors for case: invalid (-1)")
  2242  	}
  2243  }
  2244  
  2245  func TestValidatePositiveIntOrZero(t *testing.T) {
  2246  	tests := []struct {
  2247  		number int
  2248  		msg    string
  2249  	}{
  2250  		{
  2251  			number: 0,
  2252  			msg:    "valid (0)",
  2253  		},
  2254  		{
  2255  			number: 1,
  2256  			msg:    "valid (1)",
  2257  		},
  2258  	}
  2259  
  2260  	for _, test := range tests {
  2261  		allErrs := validatePositiveIntOrZero(test.number, field.NewPath("int-field"))
  2262  
  2263  		if len(allErrs) != 0 {
  2264  			t.Errorf("validatePositiveIntOrZero returned errors for case: %v", test.msg)
  2265  		}
  2266  	}
  2267  }
  2268  
  2269  func TestValidatePositiveIntOrZeroFails(t *testing.T) {
  2270  	allErrs := validatePositiveIntOrZero(-1, field.NewPath("int-field"))
  2271  
  2272  	if len(allErrs) == 0 {
  2273  		t.Error("validatePositiveIntOrZero returned no errors for case: invalid (-1)")
  2274  	}
  2275  }
  2276  
  2277  func TestValidateBuffer(t *testing.T) {
  2278  	validbuff := &v1.UpstreamBuffers{Number: 8, Size: "8k"}
  2279  	allErrs := validateBuffer(validbuff, field.NewPath("buffers-field"))
  2280  
  2281  	if len(allErrs) != 0 {
  2282  		t.Errorf("validateBuffer returned errors %v valid input %v", allErrs, validbuff)
  2283  	}
  2284  
  2285  	invalidbuff := []*v1.UpstreamBuffers{
  2286  		{
  2287  			Number: -8,
  2288  			Size:   "15m",
  2289  		},
  2290  		{
  2291  			Number: 8,
  2292  			Size:   "15G",
  2293  		},
  2294  		{
  2295  			Number: 8,
  2296  			Size:   "",
  2297  		},
  2298  	}
  2299  	for _, test := range invalidbuff {
  2300  		allErrs = validateBuffer(test, field.NewPath("buffers-field"))
  2301  		if len(allErrs) == 0 {
  2302  			t.Errorf("validateBuffer didn't return error for invalid input %v.", test)
  2303  		}
  2304  	}
  2305  }
  2306  
  2307  func TestValidateUpstreamHealthCheck(t *testing.T) {
  2308  	hc := &v1.HealthCheck{
  2309  		Enable:   true,
  2310  		Path:     "/healthz",
  2311  		Interval: "4s",
  2312  		Jitter:   "2s",
  2313  		Fails:    3,
  2314  		Passes:   2,
  2315  		Port:     8080,
  2316  		TLS: &v1.UpstreamTLS{
  2317  			Enable: true,
  2318  		},
  2319  		ConnectTimeout: "1s",
  2320  		ReadTimeout:    "1s",
  2321  		SendTimeout:    "1s",
  2322  		Headers: []v1.Header{
  2323  			{
  2324  				Name:  "Host",
  2325  				Value: "my.service",
  2326  			},
  2327  		},
  2328  		StatusMatch: "! 500",
  2329  	}
  2330  
  2331  	allErrs := validateUpstreamHealthCheck(hc, field.NewPath("healthCheck"))
  2332  
  2333  	if len(allErrs) != 0 {
  2334  		t.Errorf("validateUpstreamHealthCheck() returned errors for valid input %v", hc)
  2335  	}
  2336  }
  2337  
  2338  func TestValidateUpstreamHealthCheckFails(t *testing.T) {
  2339  	tests := []struct {
  2340  		hc *v1.HealthCheck
  2341  	}{
  2342  		{
  2343  			hc: &v1.HealthCheck{
  2344  				Enable: true,
  2345  				Path:   "/healthz//;",
  2346  			},
  2347  		},
  2348  		{
  2349  			hc: &v1.HealthCheck{
  2350  				Enable: false,
  2351  				Path:   "/healthz//;",
  2352  			},
  2353  		},
  2354  	}
  2355  
  2356  	for _, test := range tests {
  2357  		allErrs := validateUpstreamHealthCheck(test.hc, field.NewPath("healthCheck"))
  2358  
  2359  		if len(allErrs) == 0 {
  2360  			t.Errorf("validateUpstreamHealthCheck() returned no errors for invalid input %v", test.hc)
  2361  		}
  2362  	}
  2363  }
  2364  
  2365  func TestValidateStatusMatch(t *testing.T) {
  2366  	tests := []struct {
  2367  		status string
  2368  	}{
  2369  		{
  2370  			status: "200",
  2371  		},
  2372  		{
  2373  			status: "! 500",
  2374  		},
  2375  		{
  2376  			status: "200 204",
  2377  		},
  2378  		{
  2379  			status: "! 301 302",
  2380  		},
  2381  		{
  2382  			status: "200-399",
  2383  		},
  2384  		{
  2385  			status: "! 400-599",
  2386  		},
  2387  		{
  2388  			status: "301-303 307",
  2389  		},
  2390  	}
  2391  	for _, test := range tests {
  2392  		allErrs := validateStatusMatch(test.status, field.NewPath("statusMatch"))
  2393  
  2394  		if len(allErrs) != 0 {
  2395  			t.Errorf("validateStatusMatch() returned errors %v for valid input %v", allErrs, test.status)
  2396  		}
  2397  	}
  2398  }
  2399  
  2400  func TestValidateStatusMatchFails(t *testing.T) {
  2401  	tests := []struct {
  2402  		status string
  2403  		msg    string
  2404  	}{
  2405  		{
  2406  			status: "qwe",
  2407  			msg:    "Invalid: no digits",
  2408  		},
  2409  		{
  2410  			status: "!",
  2411  			msg:    "Invalid: `!` character only",
  2412  		},
  2413  		{
  2414  			status: "!500",
  2415  			msg:    "Invalid: no space after !",
  2416  		},
  2417  		{
  2418  			status: "0",
  2419  			msg:    "Invalid: status out of range (below 100)",
  2420  		},
  2421  		{
  2422  			status: "1000",
  2423  			msg:    "Invalid: status out of range (above 999)",
  2424  		},
  2425  		{
  2426  			status: "20-600",
  2427  			msg:    "Invalid: code in range is out of range",
  2428  		},
  2429  		{
  2430  			status: "! 200 ! 500",
  2431  			msg:    "Invalid: 2 exclamation symbols",
  2432  		},
  2433  		{
  2434  			status: "200 - 500",
  2435  			msg:    "Invalid: range with space around `-`",
  2436  		},
  2437  		{
  2438  			status: "500-200",
  2439  			msg:    "Invalid: range must be min < max",
  2440  		},
  2441  		{
  2442  			status: "200-200-400",
  2443  			msg:    "Invalid: range with more than 2 numbers",
  2444  		},
  2445  	}
  2446  	for _, test := range tests {
  2447  		allErrs := validateStatusMatch(test.status, field.NewPath("statusMatch"))
  2448  
  2449  		if len(allErrs) == 0 {
  2450  			t.Errorf("validateStatusMatch() returned no errors for case %v", test.msg)
  2451  		}
  2452  	}
  2453  }
  2454  
  2455  func TestValidateHeader(t *testing.T) {
  2456  	tests := []struct {
  2457  		header v1.Header
  2458  	}{
  2459  		{
  2460  			header: v1.Header{
  2461  				Name:  "Host",
  2462  				Value: "my.service",
  2463  			},
  2464  		},
  2465  		{
  2466  			header: v1.Header{
  2467  				Name:  "Host",
  2468  				Value: `\"my.service\"`,
  2469  			},
  2470  		},
  2471  	}
  2472  
  2473  	for _, test := range tests {
  2474  		allErrs := validateHeader(test.header, field.NewPath("headers"))
  2475  
  2476  		if len(allErrs) != 0 {
  2477  			t.Errorf("validateHeader() returned errors %v for valid input %v", allErrs, test.header)
  2478  		}
  2479  	}
  2480  }
  2481  
  2482  func TestValidateHeaderFails(t *testing.T) {
  2483  	tests := []struct {
  2484  		header v1.Header
  2485  		msg    string
  2486  	}{
  2487  		{
  2488  			header: v1.Header{
  2489  				Name:  "12378 qwe ",
  2490  				Value: "my.service",
  2491  			},
  2492  			msg: "Invalid name with spaces",
  2493  		},
  2494  		{
  2495  			header: v1.Header{
  2496  				Name:  "Host",
  2497  				Value: `"my.service`,
  2498  			},
  2499  			msg: `Invalid value with unescaped '"'`,
  2500  		},
  2501  		{
  2502  			header: v1.Header{
  2503  				Name:  "Host",
  2504  				Value: `my.service\`,
  2505  			},
  2506  			msg: "Invalid value with ending '\\'",
  2507  		},
  2508  		{
  2509  			header: v1.Header{
  2510  				Name:  "Host",
  2511  				Value: "$my.service",
  2512  			},
  2513  			msg: "Invalid value with '$' character",
  2514  		},
  2515  		{
  2516  			header: v1.Header{
  2517  				Name:  "Host",
  2518  				Value: "my.\\$service",
  2519  			},
  2520  			msg: "Invalid value with escaped '$' character",
  2521  		},
  2522  	}
  2523  	for _, test := range tests {
  2524  		allErrs := validateHeader(test.header, field.NewPath("headers"))
  2525  
  2526  		if len(allErrs) == 0 {
  2527  			t.Errorf("validateHeader() returned no errors for case: %v", test.msg)
  2528  		}
  2529  	}
  2530  }
  2531  
  2532  func TestValidateIntFromString(t *testing.T) {
  2533  	input := "404"
  2534  	_, errMsg := validateIntFromString(input)
  2535  
  2536  	if errMsg != "" {
  2537  		t.Errorf("validateIntFromString() returned errors %v for valid input %v", errMsg, input)
  2538  	}
  2539  }
  2540  
  2541  func TestValidateIntFromStringFails(t *testing.T) {
  2542  	input := "not a number"
  2543  	_, errMsg := validateIntFromString(input)
  2544  
  2545  	if errMsg == "" {
  2546  		t.Errorf("validateIntFromString() returned no errors for invalid input %v", input)
  2547  	}
  2548  }
  2549  
  2550  func TestRejectPlusResourcesInOSS(t *testing.T) {
  2551  	tests := []struct {
  2552  		upstream *v1.Upstream
  2553  	}{
  2554  		{
  2555  			upstream: &v1.Upstream{
  2556  				SlowStart: "10s",
  2557  			},
  2558  		},
  2559  		{
  2560  			upstream: &v1.Upstream{
  2561  				HealthCheck: &v1.HealthCheck{},
  2562  			},
  2563  		},
  2564  		{
  2565  			upstream: &v1.Upstream{
  2566  				SessionCookie: &v1.SessionCookie{},
  2567  			},
  2568  		},
  2569  		{
  2570  			upstream: &v1.Upstream{
  2571  				Queue: &v1.UpstreamQueue{},
  2572  			},
  2573  		},
  2574  	}
  2575  
  2576  	for _, test := range tests {
  2577  		allErrsOSS := rejectPlusResourcesInOSS(*test.upstream, field.NewPath("upstreams"), false)
  2578  
  2579  		if len(allErrsOSS) == 0 {
  2580  			t.Errorf("rejectPlusResourcesInOSS() returned no errors for upstream: %v", test.upstream)
  2581  		}
  2582  
  2583  		allErrsPlus := rejectPlusResourcesInOSS(*test.upstream, field.NewPath("upstreams"), true)
  2584  
  2585  		if len(allErrsPlus) != 0 {
  2586  			t.Errorf("rejectPlusResourcesInOSS() returned no errors for upstream: %v", test.upstream)
  2587  		}
  2588  	}
  2589  }
  2590  
  2591  func TestValidateQueue(t *testing.T) {
  2592  	tests := []struct {
  2593  		upstreamQueue *v1.UpstreamQueue
  2594  		msg           string
  2595  	}{
  2596  		{
  2597  			upstreamQueue: &v1.UpstreamQueue{Size: 10, Timeout: "10s"},
  2598  			msg:           "valid upstream queue with size and timeout",
  2599  		},
  2600  		{
  2601  			upstreamQueue: nil,
  2602  			msg:           "upstream queue nil",
  2603  		},
  2604  		{
  2605  			upstreamQueue: nil,
  2606  			msg:           "upstream queue nil in OSS",
  2607  		},
  2608  	}
  2609  
  2610  	for _, test := range tests {
  2611  		allErrs := validateQueue(test.upstreamQueue, field.NewPath("queue"))
  2612  		if len(allErrs) != 0 {
  2613  			t.Errorf("validateQueue() returned errors %v for valid input for the case of %s", allErrs, test.msg)
  2614  		}
  2615  	}
  2616  }
  2617  
  2618  func TestValidateQueueFails(t *testing.T) {
  2619  	tests := []struct {
  2620  		upstreamQueue *v1.UpstreamQueue
  2621  		msg           string
  2622  	}{
  2623  		{
  2624  			upstreamQueue: &v1.UpstreamQueue{Size: -1, Timeout: "10s"},
  2625  			msg:           "upstream queue with invalid size",
  2626  		},
  2627  		{
  2628  			upstreamQueue: &v1.UpstreamQueue{Size: 10, Timeout: "-10"},
  2629  			msg:           "upstream queue with invalid timeout",
  2630  		},
  2631  	}
  2632  
  2633  	for _, test := range tests {
  2634  		allErrs := validateQueue(test.upstreamQueue, field.NewPath("queue"))
  2635  		if len(allErrs) == 0 {
  2636  			t.Errorf("validateQueue() returned no errors for invalid input for the case of %s", test.msg)
  2637  		}
  2638  	}
  2639  }
  2640  
  2641  func TestValidateSessionCookie(t *testing.T) {
  2642  	tests := []struct {
  2643  		sc  *v1.SessionCookie
  2644  		msg string
  2645  	}{
  2646  		{
  2647  			sc:  &v1.SessionCookie{Enable: true, Name: "min"},
  2648  			msg: "min valid config",
  2649  		},
  2650  		{
  2651  			sc:  &v1.SessionCookie{Enable: true, Name: "test", Expires: "max"},
  2652  			msg: "valid config with expires max",
  2653  		},
  2654  		{
  2655  			sc: &v1.SessionCookie{
  2656  				Enable: true, Name: "test", Path: "/tea", Expires: "1", Domain: ".example.com", HTTPOnly: false, Secure: true,
  2657  			},
  2658  
  2659  			msg: "max valid config",
  2660  		},
  2661  	}
  2662  	for _, test := range tests {
  2663  		allErrs := validateSessionCookie(test.sc, field.NewPath("sessionCookie"))
  2664  		if len(allErrs) != 0 {
  2665  			t.Errorf("validateSessionCookie() returned errors %v for valid input for the case of: %s", allErrs, test.msg)
  2666  		}
  2667  	}
  2668  }
  2669  
  2670  func TestValidateSessionCookieFails(t *testing.T) {
  2671  	tests := []struct {
  2672  		sc  *v1.SessionCookie
  2673  		msg string
  2674  	}{
  2675  		{
  2676  			sc:  &v1.SessionCookie{Enable: true},
  2677  			msg: "missing required field: Name",
  2678  		},
  2679  		{
  2680  			sc:  &v1.SessionCookie{Enable: false},
  2681  			msg: "session cookie not enabled",
  2682  		},
  2683  		{
  2684  			sc:  &v1.SessionCookie{Enable: true, Name: "$ecret-Name"},
  2685  			msg: "invalid name format",
  2686  		},
  2687  		{
  2688  			sc:  &v1.SessionCookie{Enable: true, Name: "test", Expires: "EGGS"},
  2689  			msg: "invalid time format",
  2690  		},
  2691  		{
  2692  			sc:  &v1.SessionCookie{Enable: true, Name: "test", Path: "/ coffee"},
  2693  			msg: "invalid path format",
  2694  		},
  2695  	}
  2696  	for _, test := range tests {
  2697  		allErrs := validateSessionCookie(test.sc, field.NewPath("sessionCookie"))
  2698  		if len(allErrs) == 0 {
  2699  			t.Errorf("validateSessionCookie() returned no errors for invalid input for the case of: %v", test.msg)
  2700  		}
  2701  	}
  2702  }
  2703  
  2704  func TestValidateRedirectStatusCode(t *testing.T) {
  2705  	tests := []struct {
  2706  		code int
  2707  	}{
  2708  		{code: 301},
  2709  		{code: 302},
  2710  		{code: 307},
  2711  		{code: 308},
  2712  	}
  2713  	for _, test := range tests {
  2714  		allErrs := validateRedirectStatusCode(test.code, field.NewPath("code"))
  2715  		if len(allErrs) != 0 {
  2716  			t.Errorf("validateRedirectStatusCode(%v) returned errors %v for valid input", test.code, allErrs)
  2717  		}
  2718  	}
  2719  }
  2720  
  2721  func TestValidateRedirectStatusCodeFails(t *testing.T) {
  2722  	tests := []struct {
  2723  		code int
  2724  	}{
  2725  		{code: 309},
  2726  		{code: 299},
  2727  		{code: 305},
  2728  	}
  2729  	for _, test := range tests {
  2730  		allErrs := validateRedirectStatusCode(test.code, field.NewPath("code"))
  2731  		if len(allErrs) == 0 {
  2732  			t.Errorf("validateRedirectStatusCode(%v) returned no errors for invalid input", test.code)
  2733  		}
  2734  	}
  2735  }
  2736  
  2737  func TestIsRegexOrExactMatch(t *testing.T) {
  2738  	tests := []struct {
  2739  		path     string
  2740  		expected bool
  2741  	}{
  2742  		{
  2743  			path:     "/path",
  2744  			expected: false,
  2745  		},
  2746  		{
  2747  			path:     "~ .*\\.jpg",
  2748  			expected: true,
  2749  		},
  2750  		{
  2751  			path:     "=/exact/match",
  2752  			expected: true,
  2753  		},
  2754  	}
  2755  
  2756  	for _, test := range tests {
  2757  		result := isRegexOrExactMatch(test.path)
  2758  		if result != test.expected {
  2759  			t.Errorf("isRegexOrExactMatch(%v) returned %v but expected %v", test.path, result, test.expected)
  2760  		}
  2761  	}
  2762  }
  2763  
  2764  func TestValidateEscapedStringWithVariables(t *testing.T) {
  2765  	specialVariables := []string{"http_"}
  2766  	variables := map[string]bool{
  2767  		"request_uri": true,
  2768  		"host":        true,
  2769  	}
  2770  
  2771  	tests := []struct {
  2772  		str string
  2773  		msg string
  2774  	}{
  2775  		{
  2776  			str: "Hello World",
  2777  			msg: "single string",
  2778  		},
  2779  		{
  2780  			str: "${host}${request_uri}",
  2781  			msg: "string with variables",
  2782  		},
  2783  		{
  2784  			str: "{abc} %&*()!@#",
  2785  			msg: "string with symbols",
  2786  		},
  2787  		{
  2788  			str: "${http_authorization}",
  2789  			msg: "special variable with name",
  2790  		},
  2791  		{
  2792  			str: `
  2793  				<html>
  2794  				<body>
  2795  				<h1>Hello</h1>
  2796  				</body>
  2797  				</html>`,
  2798  			msg: "string with multiple lines",
  2799  		},
  2800  	}
  2801  
  2802  	isPlus := false
  2803  
  2804  	for _, test := range tests {
  2805  		allErrs := validateEscapedStringWithVariables(test.str, field.NewPath("body"), specialVariables, variables, isPlus)
  2806  		if len(allErrs) != 0 {
  2807  			t.Errorf("validateEscapedStringWithVariables(%v) returned errors %v for valid input for the case of: %v", test.str, allErrs, test.msg)
  2808  		}
  2809  	}
  2810  }
  2811  
  2812  func TestValidateEscapedStringWithVariablesFails(t *testing.T) {
  2813  	specialVariables := []string{"http_"}
  2814  	variables := map[string]bool{
  2815  		"request_uri": true,
  2816  		"host":        true,
  2817  	}
  2818  
  2819  	tests := []struct {
  2820  		str string
  2821  		msg string
  2822  	}{
  2823  		{
  2824  			str: "Request to $host",
  2825  			msg: "invalid variable format",
  2826  		},
  2827  		{
  2828  			str: "Request to ${host_uri}",
  2829  			msg: "invalid variable",
  2830  		},
  2831  		{
  2832  			str: "Request to ${https_authorization}",
  2833  			msg: "invalid special variable",
  2834  		},
  2835  		{
  2836  			str: `Request to host failed "`,
  2837  			msg: "unescaped double quotes",
  2838  		},
  2839  		{
  2840  			str: "Please access to ${something}.com",
  2841  			msg: "invalid variable",
  2842  		},
  2843  	}
  2844  
  2845  	isPlus := false
  2846  
  2847  	for _, test := range tests {
  2848  		allErrs := validateEscapedStringWithVariables(test.str, field.NewPath("string"), specialVariables, variables, isPlus)
  2849  		if len(allErrs) == 0 {
  2850  			t.Errorf("validateEscapedStringWithVariables(%v) returned no errors for invalid input for the case of: %v", test.str, test.msg)
  2851  		}
  2852  	}
  2853  }
  2854  
  2855  func TestValidateActionReturnType(t *testing.T) {
  2856  	tests := []struct {
  2857  		defaultType string
  2858  		msg         string
  2859  	}{
  2860  		{
  2861  			defaultType: "application/json",
  2862  			msg:         "normal MIME type",
  2863  		},
  2864  		{
  2865  			defaultType: `\"application/json\"`,
  2866  			msg:         "double quotes escaped",
  2867  		},
  2868  	}
  2869  
  2870  	for _, test := range tests {
  2871  		allErrs := validateActionReturnType(test.defaultType, field.NewPath("type"))
  2872  		if len(allErrs) != 0 {
  2873  			t.Errorf("validateActionReturnType(%v) returned errors %v for the case of: %v", test.defaultType, allErrs, test.msg)
  2874  		}
  2875  	}
  2876  }
  2877  
  2878  func TestValidateActionReturnTypeFails(t *testing.T) {
  2879  	tests := []struct {
  2880  		defaultType string
  2881  		msg         string
  2882  	}{
  2883  		{
  2884  			defaultType: "application/{json}",
  2885  			msg:         "use of forbidden symbols",
  2886  		},
  2887  		{
  2888  			defaultType: "application;json",
  2889  			msg:         "use of forbidden symbols",
  2890  		},
  2891  		{
  2892  			defaultType: `"application/json"`,
  2893  			msg:         "double quotes not escaped",
  2894  		},
  2895  	}
  2896  
  2897  	for _, test := range tests {
  2898  		allErrs := validateActionReturnType(test.defaultType, field.NewPath("type"))
  2899  		if len(allErrs) == 0 {
  2900  			t.Errorf("validateActionReturnType(%v) returned no errors for the case of: %v", test.defaultType, test.msg)
  2901  		}
  2902  	}
  2903  }
  2904  
  2905  func TestValidateActionReturn(t *testing.T) {
  2906  	tests := []*v1.ActionReturn{
  2907  		{
  2908  			Body: "Hello World",
  2909  		},
  2910  		{
  2911  			Body: "The URI is ${request_uri}",
  2912  		},
  2913  		{
  2914  			Body: "The header abc is ${http_abc}",
  2915  		},
  2916  		{
  2917  			Type: "application/json",
  2918  			Body: "Hello World",
  2919  		},
  2920  		{
  2921  			Code: 200,
  2922  			Type: "application/json",
  2923  			Body: "Hello World",
  2924  		},
  2925  	}
  2926  
  2927  	vsv := &VirtualServerValidator{isPlus: false}
  2928  
  2929  	for _, test := range tests {
  2930  		allErrs := vsv.validateActionReturn(test, field.NewPath("return"), returnBodySpecialVariables, returnBodyVariables)
  2931  		if len(allErrs) != 0 {
  2932  			t.Errorf("validateActionReturn(%v) returned errors for valid input", test)
  2933  		}
  2934  	}
  2935  }
  2936  
  2937  func TestValidateActionReturnFails(t *testing.T) {
  2938  	tests := []*v1.ActionReturn{
  2939  		{},
  2940  		{
  2941  			Body: "Hello ${somevar}",
  2942  		},
  2943  		{
  2944  			Body: "Hello ${http_%}",
  2945  		},
  2946  		{
  2947  			Code: 301,
  2948  			Body: "Hello World",
  2949  		},
  2950  		{
  2951  			Code: 200,
  2952  			Type: `application/"json"`,
  2953  			Body: "Hello World",
  2954  		},
  2955  	}
  2956  
  2957  	vsv := &VirtualServerValidator{isPlus: false}
  2958  
  2959  	for _, test := range tests {
  2960  		allErrs := vsv.validateActionReturn(test, field.NewPath("return"), returnBodySpecialVariables, returnBodyVariables)
  2961  		if len(allErrs) == 0 {
  2962  			t.Errorf("validateActionReturn(%v) returned no errors for invalid input", test)
  2963  		}
  2964  	}
  2965  }
  2966  
  2967  func TestValidateActionProxy(t *testing.T) {
  2968  	upstreamNames := map[string]sets.Empty{
  2969  		"upstream1": {},
  2970  	}
  2971  	path := "/path"
  2972  	actionProxy := &v1.ActionProxy{
  2973  		Upstream:    "upstream1",
  2974  		RewritePath: "/test",
  2975  	}
  2976  
  2977  	vsv := &VirtualServerValidator{isPlus: false}
  2978  
  2979  	allErrs := vsv.validateActionProxy(actionProxy, field.NewPath("proxy"), upstreamNames, path, false)
  2980  
  2981  	if len(allErrs) != 0 {
  2982  		t.Errorf("validateActionProxy(%+v, %v, %v) returned errors for valid input: %v", actionProxy, upstreamNames, path, allErrs)
  2983  	}
  2984  }
  2985  
  2986  func TestValidateActionProxyFails(t *testing.T) {
  2987  	upstreamNames := map[string]sets.Empty{
  2988  		"upstream1": {},
  2989  	}
  2990  	path := "/path"
  2991  	actionProxy := &v1.ActionProxy{
  2992  		Upstream: "",
  2993  	}
  2994  
  2995  	vsv := &VirtualServerValidator{isPlus: false}
  2996  
  2997  	allErrs := vsv.validateActionProxy(actionProxy, field.NewPath("proxy"), upstreamNames, path, false)
  2998  
  2999  	if len(allErrs) == 0 {
  3000  		t.Errorf("validateActionProxy(%+v, %v, %v) returned no errors for invalid input", actionProxy, upstreamNames, path)
  3001  	}
  3002  }
  3003  
  3004  func TestValidateActionProxyRewritePath(t *testing.T) {
  3005  	tests := []string{"/rewrite", "/rewrite", `/$2`}
  3006  	for _, test := range tests {
  3007  		allErrs := validateActionProxyRewritePath(test, field.NewPath("rewritePath"))
  3008  		if len(allErrs) != 0 {
  3009  			t.Errorf("validateActionProxyRewritePath(%v) returned errors for valid input: %v", test, allErrs)
  3010  		}
  3011  	}
  3012  }
  3013  
  3014  func TestValidateActionProxyRewritePathFails(t *testing.T) {
  3015  	tests := []string{`/\d{3}`, `(`, "$request_uri"}
  3016  	for _, test := range tests {
  3017  		allErrs := validateActionProxyRewritePath(test, field.NewPath("rewritePath"))
  3018  		if len(allErrs) == 0 {
  3019  			t.Errorf("validateActionProxyRewritePath(%v) returned no errors for invalid input", test)
  3020  		}
  3021  	}
  3022  }
  3023  
  3024  func TestValidateActionProxyRewritePathForRegexp(t *testing.T) {
  3025  	tests := []string{"/rewrite$1", "test", `/$2`, `\"test\"`}
  3026  	for _, test := range tests {
  3027  		allErrs := validateActionProxyRewritePathForRegexp(test, field.NewPath("rewritePath"))
  3028  		if len(allErrs) != 0 {
  3029  			t.Errorf("validateActionProxyRewritePathForRegexp(%v) returned errors for valid input: %v", test, allErrs)
  3030  		}
  3031  	}
  3032  }
  3033  
  3034  func TestValidateActionProxyRewritePathForRegexpFails(t *testing.T) {
  3035  	tests := []string{"$request_uri", `"test"`, `test\`}
  3036  	for _, test := range tests {
  3037  		allErrs := validateActionProxyRewritePathForRegexp(test, field.NewPath("rewritePath"))
  3038  		if len(allErrs) == 0 {
  3039  			t.Errorf("validateActionProxyRewritePathForRegexp(%v) returned no errors for invalid input", test)
  3040  		}
  3041  	}
  3042  }
  3043  
  3044  func TestValidateActionProxyHeader(t *testing.T) {
  3045  	tests := []struct {
  3046  		header v1.Header
  3047  	}{
  3048  		{
  3049  			header: v1.Header{
  3050  				Name:  "Host",
  3051  				Value: "my.service",
  3052  			},
  3053  		},
  3054  		{
  3055  			header: v1.Header{
  3056  				Name:  "Host",
  3057  				Value: `\"my.service\"`,
  3058  			},
  3059  		},
  3060  		{
  3061  			header: v1.Header{
  3062  				Name:  "Host",
  3063  				Value: "${request_uri}",
  3064  			},
  3065  		},
  3066  		{
  3067  			header: v1.Header{
  3068  				Name:  "Host",
  3069  				Value: "${http_some_header}",
  3070  			},
  3071  		},
  3072  		{
  3073  			header: v1.Header{
  3074  				Name:  "Host",
  3075  				Value: "${request_uri} and ${http_some_header}",
  3076  			},
  3077  		},
  3078  	}
  3079  
  3080  	vsv := &VirtualServerValidator{isPlus: false}
  3081  
  3082  	for _, test := range tests {
  3083  		allErrs := vsv.validateActionProxyHeader(test.header, field.NewPath("headers"))
  3084  
  3085  		if len(allErrs) != 0 {
  3086  			t.Errorf("validateActionProxyHeader() returned errors %v for valid input %v", allErrs, test.header)
  3087  		}
  3088  	}
  3089  }
  3090  
  3091  func TestValidateActionProxyHeaderFails(t *testing.T) {
  3092  	tests := []struct {
  3093  		header v1.Header
  3094  		msg    string
  3095  	}{
  3096  		{
  3097  			header: v1.Header{
  3098  				Name:  "12378 qwe ",
  3099  				Value: "my.service",
  3100  			},
  3101  			msg: "Invalid name with spaces",
  3102  		},
  3103  		{
  3104  			header: v1.Header{
  3105  				Name:  "Host",
  3106  				Value: `"my.service`,
  3107  			},
  3108  			msg: `Invalid value with unescaped '"'`,
  3109  		},
  3110  		{
  3111  			header: v1.Header{
  3112  				Name:  "Host",
  3113  				Value: `my.service\`,
  3114  			},
  3115  			msg: "Invalid value with ending '\\'",
  3116  		},
  3117  		{
  3118  			header: v1.Header{
  3119  				Name:  "Host",
  3120  				Value: "${realpath_root}",
  3121  			},
  3122  			msg: "Invalid variable",
  3123  		},
  3124  		{
  3125  			header: v1.Header{
  3126  				Name:  "Host",
  3127  				Value: "${sent_http_name}",
  3128  			},
  3129  			msg: "Invalid special variable",
  3130  		},
  3131  		{
  3132  			header: v1.Header{
  3133  				Name:  "Host",
  3134  				Value: "my.\\$service",
  3135  			},
  3136  			msg: "Invalid value with escaped '$' character",
  3137  		},
  3138  	}
  3139  
  3140  	vsv := &VirtualServerValidator{isPlus: false}
  3141  
  3142  	for _, test := range tests {
  3143  		allErrs := vsv.validateActionProxyHeader(test.header, field.NewPath("headers"))
  3144  
  3145  		if len(allErrs) == 0 {
  3146  			t.Errorf("validateActionProxyHeader() returned no errors for case: %v", test.msg)
  3147  		}
  3148  	}
  3149  }
  3150  
  3151  func TestValidateActionProxyRequestHeaders(t *testing.T) {
  3152  	requestHeaders := &v1.ProxyRequestHeaders{
  3153  		Set: []v1.Header{
  3154  			{
  3155  				Name:  "Host",
  3156  				Value: "nginx.org",
  3157  			},
  3158  			{
  3159  				Name:  "scheme",
  3160  				Value: "${scheme}",
  3161  			},
  3162  			{
  3163  				Name:  "user",
  3164  				Value: "${http_user}",
  3165  			},
  3166  		},
  3167  	}
  3168  
  3169  	vsv := &VirtualServerValidator{isPlus: false}
  3170  
  3171  	allErrs := vsv.validateActionProxyRequestHeaders(requestHeaders, field.NewPath("requestHeaders"))
  3172  	if len(allErrs) != 0 {
  3173  		t.Errorf("validateActionProxyRequestHeaders(%v) returned errors for valid input: %v", requestHeaders, allErrs)
  3174  	}
  3175  }
  3176  
  3177  func TestValidateActionProxyRequestHeadersFails(t *testing.T) {
  3178  	invalidHeaders := []*v1.ProxyRequestHeaders{
  3179  		{
  3180  			Set: []v1.Header{
  3181  				{
  3182  					Name:  "in va lid",
  3183  					Value: "",
  3184  				},
  3185  			},
  3186  		},
  3187  		{
  3188  			Set: []v1.Header{
  3189  				{
  3190  					Name:  "Host",
  3191  					Value: "$var",
  3192  				},
  3193  			},
  3194  		},
  3195  		{
  3196  			Set: []v1.Header{
  3197  				{
  3198  					Name:  "",
  3199  					Value: "nginx.org",
  3200  				},
  3201  			},
  3202  		},
  3203  		{
  3204  			Set: []v1.Header{
  3205  				{
  3206  					Name:  "Host",
  3207  					Value: "${http_%}",
  3208  				},
  3209  			},
  3210  		},
  3211  	}
  3212  
  3213  	vsv := &VirtualServerValidator{isPlus: false}
  3214  
  3215  	for _, headers := range invalidHeaders {
  3216  		allErrs := vsv.validateActionProxyRequestHeaders(headers, field.NewPath("requestHeaders"))
  3217  		if len(allErrs) == 0 {
  3218  			t.Errorf("validateActionProxyRequestHeaders(%v) returned no errors for invalid input", headers)
  3219  		}
  3220  	}
  3221  }
  3222  
  3223  func TestValidateActionProxyResponseHeaders(t *testing.T) {
  3224  	tests := []struct {
  3225  		responseHeaders *v1.ProxyResponseHeaders
  3226  	}{
  3227  		{
  3228  			responseHeaders: &v1.ProxyResponseHeaders{
  3229  				Hide:   []string{"Header"},
  3230  				Pass:   []string{"Header"},
  3231  				Ignore: []string{"Expires"},
  3232  				Add: []v1.AddHeader{
  3233  					{
  3234  						Header: v1.Header{
  3235  							Name:  "Host",
  3236  							Value: "nginx.org",
  3237  						},
  3238  						Always: false,
  3239  					},
  3240  				},
  3241  			},
  3242  		},
  3243  		{
  3244  			responseHeaders: &v1.ProxyResponseHeaders{
  3245  				Hide: []string{"Header"},
  3246  			},
  3247  		},
  3248  		{
  3249  			responseHeaders: &v1.ProxyResponseHeaders{
  3250  				Pass: []string{"Header"},
  3251  			},
  3252  		},
  3253  		{
  3254  			responseHeaders: &v1.ProxyResponseHeaders{
  3255  				Ignore: []string{"Expires"},
  3256  			},
  3257  		},
  3258  		{
  3259  			responseHeaders: &v1.ProxyResponseHeaders{
  3260  				Add: []v1.AddHeader{
  3261  					{
  3262  						Header: v1.Header{
  3263  							Name:  "Host",
  3264  							Value: "nginx.org",
  3265  						},
  3266  						Always: false,
  3267  					},
  3268  					{
  3269  						Header: v1.Header{
  3270  							Name:  "uri",
  3271  							Value: "${request_uri}",
  3272  						},
  3273  					},
  3274  					{
  3275  						Header: v1.Header{
  3276  							Name:  "abc",
  3277  							Value: "${http_abc}",
  3278  						},
  3279  					},
  3280  				},
  3281  			},
  3282  		},
  3283  	}
  3284  
  3285  	vsv := &VirtualServerValidator{isPlus: false}
  3286  
  3287  	for _, test := range tests {
  3288  		allErrs := vsv.validateActionProxyResponseHeaders(test.responseHeaders, field.NewPath("responseHeaders"))
  3289  		if len(allErrs) != 0 {
  3290  			t.Errorf("validateActionProxyResponseHeaders(%v) returned errors for valid input: %v", test.responseHeaders, allErrs)
  3291  		}
  3292  	}
  3293  }
  3294  
  3295  func TestValidateActionProxyResponseHeadersFails(t *testing.T) {
  3296  	tests := []struct {
  3297  		responseHeaders *v1.ProxyResponseHeaders
  3298  		msg             string
  3299  	}{
  3300  		{
  3301  			responseHeaders: &v1.ProxyResponseHeaders{
  3302  				Hide:   []string{""},
  3303  				Pass:   []string{""},
  3304  				Ignore: []string{""},
  3305  				Add: []v1.AddHeader{
  3306  					{
  3307  						Header: v1.Header{
  3308  							Name:  "",
  3309  							Value: "nginx.org",
  3310  						},
  3311  					},
  3312  				},
  3313  			},
  3314  			msg: "all fields invalid",
  3315  		},
  3316  		{
  3317  			responseHeaders: &v1.ProxyResponseHeaders{
  3318  				Hide: []string{"invalid header"},
  3319  			},
  3320  			msg: "invalid hide headers",
  3321  		},
  3322  		{
  3323  			responseHeaders: &v1.ProxyResponseHeaders{
  3324  				Pass: []string{"$invalid"},
  3325  			},
  3326  			msg: "invalid pass headers",
  3327  		},
  3328  		{
  3329  			responseHeaders: &v1.ProxyResponseHeaders{
  3330  				Ignore: []string{"1234 invalid"},
  3331  			},
  3332  			msg: "invalid ignore headers",
  3333  		},
  3334  		{
  3335  			responseHeaders: &v1.ProxyResponseHeaders{
  3336  				Add: []v1.AddHeader{
  3337  					{
  3338  						Header: v1.Header{
  3339  							Name:  "$invalid 123",
  3340  							Value: "nginx.org",
  3341  						},
  3342  						Always: false,
  3343  					},
  3344  				},
  3345  			},
  3346  			msg: "invalid Add header name",
  3347  		},
  3348  		{
  3349  			responseHeaders: &v1.ProxyResponseHeaders{
  3350  				Add: []v1.AddHeader{
  3351  					{
  3352  						Header: v1.Header{
  3353  							Name:  "Host",
  3354  							Value: "${invalid}",
  3355  						},
  3356  						Always: false,
  3357  					},
  3358  				},
  3359  			},
  3360  			msg: "invalid Add header value",
  3361  		},
  3362  	}
  3363  
  3364  	vsv := &VirtualServerValidator{isPlus: false}
  3365  
  3366  	for _, test := range tests {
  3367  		allErrs := vsv.validateActionProxyResponseHeaders(test.responseHeaders, field.NewPath("responseHeaders"))
  3368  		if len(allErrs) == 0 {
  3369  			t.Errorf("validateActionProxyResponseHeaders(%v) returned no errors for invalid input for the case of %v", test.responseHeaders, test.msg)
  3370  		}
  3371  	}
  3372  }
  3373  
  3374  func TestValidateIgnoreHeaders(t *testing.T) {
  3375  	var ignoreHeaders []string
  3376  
  3377  	for header := range validIgnoreHeaders {
  3378  		ignoreHeaders = append(ignoreHeaders, header)
  3379  	}
  3380  
  3381  	allErrs := validateIgnoreHeaders(ignoreHeaders, field.NewPath("ignoreHeaders"))
  3382  	if len(allErrs) != 0 {
  3383  		t.Errorf("validateIgnoreHeaders(%v) returned errors for valid input: %v", ignoreHeaders, allErrs)
  3384  	}
  3385  }
  3386  
  3387  func TestValidateIgnoreHeadersFails(t *testing.T) {
  3388  	ignoreHeaders := []string{
  3389  		"Host",
  3390  		"Connection",
  3391  	}
  3392  
  3393  	allErrs := validateIgnoreHeaders(ignoreHeaders, field.NewPath("ignoreHeaders"))
  3394  	if len(allErrs) == 0 {
  3395  		t.Errorf("validateIgnoreHeaders(%v) returned no errors for invalid input", ignoreHeaders)
  3396  	}
  3397  }
  3398  
  3399  func TestValidateStringNoVariables(t *testing.T) {
  3400  	tests := []string{
  3401  		"string",
  3402  		"endWith$",
  3403  		"withNumber$1",
  3404  		"abcййй",
  3405  		"abcййй$1",
  3406  		"",
  3407  	}
  3408  
  3409  	for _, test := range tests {
  3410  		allErrs := validateStringNoVariables(test, field.NewPath("rewritePath"))
  3411  		if len(allErrs) != 0 {
  3412  			t.Errorf("validateStringNoVariables(%v) returned errors for valid input: %v", test, allErrs)
  3413  		}
  3414  	}
  3415  }
  3416  
  3417  func TestValidateStringNoVariablesFails(t *testing.T) {
  3418  	tests := []string{
  3419  		"$var",
  3420  		"abcйй$й",
  3421  		"$$",
  3422  	}
  3423  
  3424  	for _, test := range tests {
  3425  		allErrs := validateStringNoVariables(test, field.NewPath("rewritePath"))
  3426  		if len(allErrs) == 0 {
  3427  			t.Errorf("validateStringNoVariables(%v) returned no errors for invalid input", test)
  3428  		}
  3429  	}
  3430  }
  3431  
  3432  func TestValidateActionReturnCode(t *testing.T) {
  3433  	codes := []int{200, 201, 400, 404, 500, 502, 599}
  3434  	for _, c := range codes {
  3435  		allErrs := validateActionReturnCode(c, field.NewPath("code"))
  3436  		if len(allErrs) != 0 {
  3437  			t.Errorf("validateActionReturnCode(%v) returned errors for valid input: %v", c, allErrs)
  3438  		}
  3439  	}
  3440  }
  3441  
  3442  func TestValidateActionReturnCodeFails(t *testing.T) {
  3443  	codes := []int{0, -1, 199, 300, 399, 600, 999}
  3444  	for _, c := range codes {
  3445  		allErrs := validateActionReturnCode(c, field.NewPath("code"))
  3446  		if len(allErrs) == 0 {
  3447  			t.Errorf("validateActionReturnCode(%v) returned no errors for invalid input", c)
  3448  		}
  3449  	}
  3450  }
  3451  
  3452  func TestErrorPageHasRequiredFields(t *testing.T) {
  3453  	tests := []struct {
  3454  		errorPage v1.ErrorPage
  3455  		expected  bool
  3456  	}{
  3457  		{
  3458  			errorPage: v1.ErrorPage{
  3459  				Codes:    nil,
  3460  				Return:   nil,
  3461  				Redirect: nil,
  3462  			},
  3463  			expected: false,
  3464  		},
  3465  		{
  3466  			errorPage: v1.ErrorPage{
  3467  				Codes:    nil,
  3468  				Return:   &v1.ErrorPageReturn{},
  3469  				Redirect: &v1.ErrorPageRedirect{},
  3470  			},
  3471  			expected: false,
  3472  		},
  3473  		{
  3474  			errorPage: v1.ErrorPage{
  3475  				Codes:    nil,
  3476  				Return:   &v1.ErrorPageReturn{},
  3477  				Redirect: nil,
  3478  			},
  3479  			expected: true,
  3480  		},
  3481  		{
  3482  			errorPage: v1.ErrorPage{
  3483  				Codes:    nil,
  3484  				Return:   nil,
  3485  				Redirect: &v1.ErrorPageRedirect{},
  3486  			},
  3487  			expected: true,
  3488  		},
  3489  	}
  3490  
  3491  	for _, test := range tests {
  3492  		result := errorPageHasRequiredFields(test.errorPage)
  3493  		if result != test.expected {
  3494  			t.Errorf("errorPageHasRequiredFields(%v) returned %v but expected %v", test.errorPage, result, test.expected)
  3495  		}
  3496  	}
  3497  }
  3498  
  3499  func TestValidateErrorPage(t *testing.T) {
  3500  	tests := []v1.ErrorPage{
  3501  		{
  3502  			Codes: []int{400, 404},
  3503  			Return: &v1.ErrorPageReturn{
  3504  				ActionReturn: v1.ActionReturn{
  3505  					Body: "Hello World",
  3506  				},
  3507  			},
  3508  			Redirect: nil,
  3509  		},
  3510  		{
  3511  			Codes:  []int{400, 404},
  3512  			Return: nil,
  3513  			Redirect: &v1.ErrorPageRedirect{
  3514  				ActionRedirect: v1.ActionRedirect{
  3515  					URL: "http://nginx.com",
  3516  				},
  3517  			},
  3518  		},
  3519  	}
  3520  
  3521  	vsv := &VirtualServerValidator{isPlus: false}
  3522  
  3523  	for _, ep := range tests {
  3524  		allErrs := vsv.validateErrorPage(ep, field.NewPath("errorPage"))
  3525  		if len(allErrs) != 0 {
  3526  			t.Errorf("validateErrorPage(%v) returned errors for valid input: %v", ep, allErrs)
  3527  		}
  3528  	}
  3529  }
  3530  
  3531  func TestValidateErrorPageFails(t *testing.T) {
  3532  	tests := []v1.ErrorPage{
  3533  		{},
  3534  		{
  3535  			Codes:    []int{400, 404},
  3536  			Return:   &v1.ErrorPageReturn{},
  3537  			Redirect: &v1.ErrorPageRedirect{},
  3538  		},
  3539  		{
  3540  			Codes:    []int{100, 700},
  3541  			Return:   &v1.ErrorPageReturn{},
  3542  			Redirect: nil,
  3543  		},
  3544  		{
  3545  			Codes:    nil,
  3546  			Return:   &v1.ErrorPageReturn{},
  3547  			Redirect: nil,
  3548  		},
  3549  	}
  3550  
  3551  	vsv := &VirtualServerValidator{isPlus: false}
  3552  
  3553  	for _, ep := range tests {
  3554  		allErrs := vsv.validateErrorPage(ep, field.NewPath("errorPage"))
  3555  		if len(allErrs) == 0 {
  3556  			t.Errorf("validateErrorPage(%v) returned no errors for invalid input", ep)
  3557  		}
  3558  	}
  3559  }
  3560  
  3561  func TestValidateErrorPageReturn(t *testing.T) {
  3562  	tests := []v1.ErrorPageReturn{
  3563  		{
  3564  			ActionReturn: v1.ActionReturn{
  3565  				Code: 200,
  3566  				Type: "",
  3567  				Body: "Could not process request, try again",
  3568  			},
  3569  			Headers: nil,
  3570  		},
  3571  		{
  3572  			ActionReturn: v1.ActionReturn{
  3573  				Code: 0,
  3574  				Type: "",
  3575  				Body: "Could not process request, try again. Upstream status ${upstream_status}",
  3576  			},
  3577  			Headers: []v1.Header{
  3578  				{
  3579  					Name:  "Set-Cookie",
  3580  					Value: "mycookie=true",
  3581  				},
  3582  			},
  3583  		},
  3584  		{
  3585  			ActionReturn: v1.ActionReturn{
  3586  				Code: 200,
  3587  				Type: "application/json",
  3588  				Body: `{\"message\": \"Could not process request, try again\", \"upstream_status\": \"${upstream_status}\"}`,
  3589  			},
  3590  			Headers: nil,
  3591  		},
  3592  	}
  3593  
  3594  	vsv := &VirtualServerValidator{isPlus: false}
  3595  
  3596  	for _, epr := range tests {
  3597  		// FIXME #nosec G601
  3598  		allErrs := vsv.validateErrorPageReturn(&epr, field.NewPath("return"))
  3599  		if len(allErrs) != 0 {
  3600  			t.Errorf("validateErrorPageReturn(%v) returned errors for valid input: %v", epr, allErrs)
  3601  		}
  3602  	}
  3603  }
  3604  
  3605  func TestValidateErrorPageReturnFails(t *testing.T) {
  3606  	tests := []struct {
  3607  		msg string
  3608  		epr v1.ErrorPageReturn
  3609  	}{
  3610  		{
  3611  			msg: "empty body",
  3612  			epr: v1.ErrorPageReturn{
  3613  				ActionReturn: v1.ActionReturn{
  3614  					Code: 200,
  3615  					Type: "application/json",
  3616  					Body: "",
  3617  				},
  3618  			},
  3619  		},
  3620  		{
  3621  			msg: "unescaped double quotes",
  3622  			epr: v1.ErrorPageReturn{
  3623  				ActionReturn: v1.ActionReturn{
  3624  					Code: 200,
  3625  					Type: "",
  3626  					Body: ` "Oops, Could not process request"`,
  3627  				},
  3628  			},
  3629  		},
  3630  		{
  3631  			msg: "invalid variable",
  3632  			epr: v1.ErrorPageReturn{
  3633  				ActionReturn: v1.ActionReturn{
  3634  					Code: 0,
  3635  					Type: "",
  3636  					Body: "Could not process request, response with invalid var: ${invalid}",
  3637  				},
  3638  			},
  3639  		},
  3640  		{
  3641  			msg: "invalid cookie name",
  3642  			epr: v1.ErrorPageReturn{
  3643  				ActionReturn: v1.ActionReturn{
  3644  					Code: 200,
  3645  					Type: "application/json",
  3646  					Body: `{\"message\": \"Could not process request, try again\", \"status\": \"${status}\"}`,
  3647  				},
  3648  				Headers: []v1.Header{
  3649  					{
  3650  						Name:  "Set-Cookie$_%^$  -",
  3651  						Value: "mycookie=true",
  3652  					},
  3653  				},
  3654  			},
  3655  		},
  3656  	}
  3657  
  3658  	vsv := &VirtualServerValidator{isPlus: false}
  3659  
  3660  	for _, test := range tests {
  3661  		allErrs := vsv.validateErrorPageReturn(&test.epr, field.NewPath("return"))
  3662  		if len(allErrs) == 0 {
  3663  			t.Errorf("validateErrorPageReturn(%v) returned no errors for invalid input for the case of %v", test.epr, test.msg)
  3664  		}
  3665  	}
  3666  }
  3667  
  3668  func TestValidateErrorPageRedirect(t *testing.T) {
  3669  	tests := []v1.ErrorPageRedirect{
  3670  		{
  3671  			ActionRedirect: v1.ActionRedirect{
  3672  				URL:  "http://nginx.com",
  3673  				Code: 301,
  3674  			},
  3675  		},
  3676  		{
  3677  			ActionRedirect: v1.ActionRedirect{
  3678  				URL:  "${scheme}://nginx.com",
  3679  				Code: 302,
  3680  			},
  3681  		},
  3682  	}
  3683  
  3684  	vsv := &VirtualServerValidator{isPlus: false}
  3685  
  3686  	for _, epr := range tests {
  3687  		// FIXME #nosec G601
  3688  		allErrs := vsv.validateErrorPageRedirect(&epr, field.NewPath("redirect"))
  3689  		if len(allErrs) != 0 {
  3690  			t.Errorf("validateErrorPageRedirect(%v) returned errors for valid input: %v", epr, allErrs)
  3691  		}
  3692  	}
  3693  }
  3694  
  3695  func TestValidateErrorPageRedirectFails(t *testing.T) {
  3696  	tests := []v1.ErrorPageRedirect{
  3697  		{
  3698  			ActionRedirect: v1.ActionRedirect{
  3699  				URL:  "",
  3700  				Code: 301,
  3701  			},
  3702  		},
  3703  		{
  3704  			ActionRedirect: v1.ActionRedirect{
  3705  				URL:  `"http://nginx.com"`,
  3706  				Code: 301,
  3707  			},
  3708  		},
  3709  		{
  3710  			ActionRedirect: v1.ActionRedirect{
  3711  				URL:  "http://nginx.com",
  3712  				Code: 100,
  3713  			},
  3714  		},
  3715  		{
  3716  			ActionRedirect: v1.ActionRedirect{
  3717  				URL:  "$scheme://nginx.com",
  3718  				Code: 302,
  3719  			},
  3720  		},
  3721  		{
  3722  			ActionRedirect: v1.ActionRedirect{
  3723  				URL:  "https://${host}.com",
  3724  				Code: 302,
  3725  			},
  3726  		},
  3727  	}
  3728  
  3729  	vsv := &VirtualServerValidator{isPlus: false}
  3730  
  3731  	for _, epr := range tests {
  3732  		// FIXME #nosec G601
  3733  		allErrs := vsv.validateErrorPageRedirect(&epr, field.NewPath("redirect"))
  3734  		if len(allErrs) == 0 {
  3735  			t.Errorf("validateErrorPageRedirect(%v) returned no errors for invalid input", epr)
  3736  		}
  3737  	}
  3738  }
  3739  
  3740  func TestValidateErrorPageHeader(t *testing.T) {
  3741  	tests := []v1.Header{
  3742  		{
  3743  			Name:  "Header-Name",
  3744  			Value: "",
  3745  		},
  3746  		{
  3747  			Name:  "Header-Name",
  3748  			Value: "Value",
  3749  		},
  3750  		{
  3751  			Name:  "Header-Name",
  3752  			Value: "${upstream_status}",
  3753  		},
  3754  	}
  3755  
  3756  	vsv := &VirtualServerValidator{isPlus: false}
  3757  
  3758  	for _, test := range tests {
  3759  		allErrs := vsv.validateErrorPageHeader(test, field.NewPath("header"))
  3760  		if len(allErrs) != 0 {
  3761  			t.Errorf("validateErrorPageHeader(%v) returned errors for valid input", test)
  3762  		}
  3763  	}
  3764  }
  3765  
  3766  func TestValidateErrorPageHeaderFails(t *testing.T) {
  3767  	tests := []v1.Header{
  3768  		{
  3769  			Name:  "",
  3770  			Value: "",
  3771  		},
  3772  		{
  3773  			Name:  "Header-!!#Name",
  3774  			Value: "",
  3775  		},
  3776  		{
  3777  			Name:  "Header-Name",
  3778  			Value: "$novar",
  3779  		},
  3780  		{
  3781  			Name:  "Header-Name",
  3782  			Value: "${invalid_var}",
  3783  		},
  3784  		{
  3785  			Name:  "Header-Name",
  3786  			Value: `unescaped "`,
  3787  		},
  3788  	}
  3789  
  3790  	vsv := &VirtualServerValidator{isPlus: false}
  3791  
  3792  	for _, test := range tests {
  3793  		allErrs := vsv.validateErrorPageHeader(test, field.NewPath("header"))
  3794  		if len(allErrs) == 0 {
  3795  			t.Errorf("validateErrorPageHeader(%v) returned no errors for invalid input", test)
  3796  		}
  3797  	}
  3798  }