github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/configs/virtualserver_test.go (about)

     1  package configs
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/google/go-cmp/cmp"
    10  	"github.com/nginxinc/kubernetes-ingress/internal/configs/version2"
    11  	"github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets"
    12  	"github.com/nginxinc/kubernetes-ingress/internal/nginx"
    13  	conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
    14  	api_v1 "k8s.io/api/core/v1"
    15  	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/apimachinery/pkg/runtime"
    17  )
    18  
    19  func createPointerFromBool(b bool) *bool {
    20  	return &b
    21  }
    22  
    23  func TestVirtualServerExString(t *testing.T) {
    24  	tests := []struct {
    25  		input    *VirtualServerEx
    26  		expected string
    27  	}{
    28  		{
    29  			input: &VirtualServerEx{
    30  				VirtualServer: &conf_v1.VirtualServer{
    31  					ObjectMeta: meta_v1.ObjectMeta{
    32  						Name:      "cafe",
    33  						Namespace: "default",
    34  					},
    35  				},
    36  			},
    37  			expected: "default/cafe",
    38  		},
    39  		{
    40  			input:    &VirtualServerEx{},
    41  			expected: "VirtualServerEx has no VirtualServer",
    42  		},
    43  		{
    44  			input:    nil,
    45  			expected: "<nil>",
    46  		},
    47  	}
    48  
    49  	for _, test := range tests {
    50  		result := test.input.String()
    51  		if result != test.expected {
    52  			t.Errorf("VirtualServerEx.String() returned %v but expected %v", result, test.expected)
    53  		}
    54  	}
    55  }
    56  
    57  func TestGenerateEndpointsKey(t *testing.T) {
    58  	serviceNamespace := "default"
    59  	serviceName := "test"
    60  	var port uint16 = 80
    61  
    62  	tests := []struct {
    63  		subselector map[string]string
    64  		expected    string
    65  	}{
    66  		{
    67  			subselector: nil,
    68  			expected:    "default/test:80",
    69  		},
    70  		{
    71  			subselector: map[string]string{"version": "v1"},
    72  			expected:    "default/test_version=v1:80",
    73  		},
    74  	}
    75  
    76  	for _, test := range tests {
    77  		result := GenerateEndpointsKey(serviceNamespace, serviceName, test.subselector, port)
    78  		if result != test.expected {
    79  			t.Errorf("GenerateEndpointsKey() returned %q but expected %q", result, test.expected)
    80  		}
    81  
    82  	}
    83  }
    84  
    85  func TestUpstreamNamerForVirtualServer(t *testing.T) {
    86  	virtualServer := conf_v1.VirtualServer{
    87  		ObjectMeta: meta_v1.ObjectMeta{
    88  			Name:      "cafe",
    89  			Namespace: "default",
    90  		},
    91  	}
    92  	upstreamNamer := newUpstreamNamerForVirtualServer(&virtualServer)
    93  	upstream := "test"
    94  
    95  	expected := "vs_default_cafe_test"
    96  
    97  	result := upstreamNamer.GetNameForUpstream(upstream)
    98  	if result != expected {
    99  		t.Errorf("GetNameForUpstream() returned %q but expected %q", result, expected)
   100  	}
   101  }
   102  
   103  func TestUpstreamNamerForVirtualServerRoute(t *testing.T) {
   104  	virtualServer := conf_v1.VirtualServer{
   105  		ObjectMeta: meta_v1.ObjectMeta{
   106  			Name:      "cafe",
   107  			Namespace: "default",
   108  		},
   109  	}
   110  	virtualServerRoute := conf_v1.VirtualServerRoute{
   111  		ObjectMeta: meta_v1.ObjectMeta{
   112  			Name:      "coffee",
   113  			Namespace: "default",
   114  		},
   115  	}
   116  	upstreamNamer := newUpstreamNamerForVirtualServerRoute(&virtualServer, &virtualServerRoute)
   117  	upstream := "test"
   118  
   119  	expected := "vs_default_cafe_vsr_default_coffee_test"
   120  
   121  	result := upstreamNamer.GetNameForUpstream(upstream)
   122  	if result != expected {
   123  		t.Errorf("GetNameForUpstream() returned %q but expected %q", result, expected)
   124  	}
   125  }
   126  
   127  func TestVariableNamerSafeNsName(t *testing.T) {
   128  	virtualServer := conf_v1.VirtualServer{
   129  		ObjectMeta: meta_v1.ObjectMeta{
   130  			Name:      "cafe-test",
   131  			Namespace: "default",
   132  		},
   133  	}
   134  
   135  	expected := "default_cafe_test"
   136  
   137  	variableNamer := newVariableNamer(&virtualServer)
   138  
   139  	if variableNamer.safeNsName != expected {
   140  		t.Errorf(
   141  			"newVariableNamer() returned variableNamer with safeNsName=%q but expected %q",
   142  			variableNamer.safeNsName,
   143  			expected,
   144  		)
   145  	}
   146  }
   147  
   148  func TestVariableNamer(t *testing.T) {
   149  	virtualServer := conf_v1.VirtualServer{
   150  		ObjectMeta: meta_v1.ObjectMeta{
   151  			Name:      "cafe",
   152  			Namespace: "default",
   153  		},
   154  	}
   155  	variableNamer := newVariableNamer(&virtualServer)
   156  
   157  	// GetNameForSplitClientVariable()
   158  	index := 0
   159  
   160  	expected := "$vs_default_cafe_splits_0"
   161  
   162  	result := variableNamer.GetNameForSplitClientVariable(index)
   163  	if result != expected {
   164  		t.Errorf("GetNameForSplitClientVariable() returned %q but expected %q", result, expected)
   165  	}
   166  
   167  	// GetNameForVariableForMatchesRouteMap()
   168  	matchesIndex := 1
   169  	matchIndex := 2
   170  	conditionIndex := 3
   171  
   172  	expected = "$vs_default_cafe_matches_1_match_2_cond_3"
   173  
   174  	result = variableNamer.GetNameForVariableForMatchesRouteMap(matchesIndex, matchIndex, conditionIndex)
   175  	if result != expected {
   176  		t.Errorf("GetNameForVariableForMatchesRouteMap() returned %q but expected %q", result, expected)
   177  	}
   178  
   179  	// GetNameForVariableForMatchesRouteMainMap()
   180  	matchesIndex = 2
   181  
   182  	expected = "$vs_default_cafe_matches_2"
   183  
   184  	result = variableNamer.GetNameForVariableForMatchesRouteMainMap(matchesIndex)
   185  	if result != expected {
   186  		t.Errorf("GetNameForVariableForMatchesRouteMainMap() returned %q but expected %q", result, expected)
   187  	}
   188  }
   189  
   190  func TestGenerateVirtualServerConfig(t *testing.T) {
   191  	virtualServerEx := VirtualServerEx{
   192  		VirtualServer: &conf_v1.VirtualServer{
   193  			ObjectMeta: meta_v1.ObjectMeta{
   194  				Name:      "cafe",
   195  				Namespace: "default",
   196  			},
   197  			Spec: conf_v1.VirtualServerSpec{
   198  				Host: "cafe.example.com",
   199  				Upstreams: []conf_v1.Upstream{
   200  					{
   201  						Name:    "tea",
   202  						Service: "tea-svc",
   203  						Port:    80,
   204  					},
   205  					{
   206  						Name:        "tea-latest",
   207  						Service:     "tea-svc",
   208  						Subselector: map[string]string{"version": "v1"},
   209  						Port:        80,
   210  					},
   211  					{
   212  						Name:    "coffee",
   213  						Service: "coffee-svc",
   214  						Port:    80,
   215  					},
   216  				},
   217  				Routes: []conf_v1.Route{
   218  					{
   219  						Path: "/tea",
   220  						Action: &conf_v1.Action{
   221  							Pass: "tea",
   222  						},
   223  					},
   224  					{
   225  						Path: "/tea-latest",
   226  						Action: &conf_v1.Action{
   227  							Pass: "tea-latest",
   228  						},
   229  					},
   230  					{
   231  						Path:  "/coffee",
   232  						Route: "default/coffee",
   233  					},
   234  					{
   235  						Path:  "/subtea",
   236  						Route: "default/subtea",
   237  					},
   238  					{
   239  						Path: "/coffee-errorpage",
   240  						Action: &conf_v1.Action{
   241  							Pass: "coffee",
   242  						},
   243  						ErrorPages: []conf_v1.ErrorPage{
   244  							{
   245  								Codes: []int{401, 403},
   246  								Redirect: &conf_v1.ErrorPageRedirect{
   247  									ActionRedirect: conf_v1.ActionRedirect{
   248  										URL:  "http://nginx.com",
   249  										Code: 301,
   250  									},
   251  								},
   252  							},
   253  						},
   254  					},
   255  					{
   256  						Path:  "/coffee-errorpage-subroute",
   257  						Route: "default/subcoffee",
   258  						ErrorPages: []conf_v1.ErrorPage{
   259  							{
   260  								Codes: []int{401, 403},
   261  								Redirect: &conf_v1.ErrorPageRedirect{
   262  									ActionRedirect: conf_v1.ActionRedirect{
   263  										URL:  "http://nginx.com",
   264  										Code: 301,
   265  									},
   266  								},
   267  							},
   268  						},
   269  					},
   270  				},
   271  			},
   272  		},
   273  		Endpoints: map[string][]string{
   274  			"default/tea-svc:80": {
   275  				"10.0.0.20:80",
   276  			},
   277  			"default/tea-svc_version=v1:80": {
   278  				"10.0.0.30:80",
   279  			},
   280  			"default/coffee-svc:80": {
   281  				"10.0.0.40:80",
   282  			},
   283  			"default/sub-tea-svc_version=v1:80": {
   284  				"10.0.0.50:80",
   285  			},
   286  		},
   287  		VirtualServerRoutes: []*conf_v1.VirtualServerRoute{
   288  			{
   289  				ObjectMeta: meta_v1.ObjectMeta{
   290  					Name:      "coffee",
   291  					Namespace: "default",
   292  				},
   293  				Spec: conf_v1.VirtualServerRouteSpec{
   294  					Host: "cafe.example.com",
   295  					Upstreams: []conf_v1.Upstream{
   296  						{
   297  							Name:    "coffee",
   298  							Service: "coffee-svc",
   299  							Port:    80,
   300  						},
   301  					},
   302  					Subroutes: []conf_v1.Route{
   303  						{
   304  							Path: "/coffee",
   305  							Action: &conf_v1.Action{
   306  								Pass: "coffee",
   307  							},
   308  						},
   309  					},
   310  				},
   311  			},
   312  			{
   313  				ObjectMeta: meta_v1.ObjectMeta{
   314  					Name:      "subtea",
   315  					Namespace: "default",
   316  				},
   317  				Spec: conf_v1.VirtualServerRouteSpec{
   318  					Host: "cafe.example.com",
   319  					Upstreams: []conf_v1.Upstream{
   320  						{
   321  							Name:        "subtea",
   322  							Service:     "sub-tea-svc",
   323  							Port:        80,
   324  							Subselector: map[string]string{"version": "v1"},
   325  						},
   326  					},
   327  					Subroutes: []conf_v1.Route{
   328  						{
   329  							Path: "/subtea",
   330  							Action: &conf_v1.Action{
   331  								Pass: "subtea",
   332  							},
   333  						},
   334  					},
   335  				},
   336  			},
   337  			{
   338  				ObjectMeta: meta_v1.ObjectMeta{
   339  					Name:      "subcoffee",
   340  					Namespace: "default",
   341  				},
   342  				Spec: conf_v1.VirtualServerRouteSpec{
   343  					Host: "cafe.example.com",
   344  					Upstreams: []conf_v1.Upstream{
   345  						{
   346  							Name:    "coffee",
   347  							Service: "coffee-svc",
   348  							Port:    80,
   349  						},
   350  					},
   351  					Subroutes: []conf_v1.Route{
   352  						{
   353  							Path: "/coffee-errorpage-subroute",
   354  							Action: &conf_v1.Action{
   355  								Pass: "coffee",
   356  							},
   357  						},
   358  						{
   359  							Path: "/coffee-errorpage-subroute-defined",
   360  							Action: &conf_v1.Action{
   361  								Pass: "coffee",
   362  							},
   363  							ErrorPages: []conf_v1.ErrorPage{
   364  								{
   365  									Codes: []int{502, 503},
   366  									Return: &conf_v1.ErrorPageReturn{
   367  										ActionReturn: conf_v1.ActionReturn{
   368  											Code: 200,
   369  											Type: "text/plain",
   370  											Body: "All Good",
   371  										},
   372  									},
   373  								},
   374  							},
   375  						},
   376  					},
   377  				},
   378  			},
   379  		},
   380  	}
   381  
   382  	baseCfgParams := ConfigParams{
   383  		ServerTokens:    "off",
   384  		Keepalive:       16,
   385  		ServerSnippets:  []string{"# server snippet"},
   386  		ProxyProtocol:   true,
   387  		SetRealIPFrom:   []string{"0.0.0.0/0"},
   388  		RealIPHeader:    "X-Real-IP",
   389  		RealIPRecursive: true,
   390  	}
   391  
   392  	expected := version2.VirtualServerConfig{
   393  		Upstreams: []version2.Upstream{
   394  			{
   395  				UpstreamLabels: version2.UpstreamLabels{
   396  					Service:           "tea-svc",
   397  					ResourceType:      "virtualserver",
   398  					ResourceName:      "cafe",
   399  					ResourceNamespace: "default",
   400  				},
   401  				Name: "vs_default_cafe_tea",
   402  				Servers: []version2.UpstreamServer{
   403  					{
   404  						Address: "10.0.0.20:80",
   405  					},
   406  				},
   407  				Keepalive: 16,
   408  			},
   409  			{
   410  				UpstreamLabels: version2.UpstreamLabels{
   411  					Service:           "tea-svc",
   412  					ResourceType:      "virtualserver",
   413  					ResourceName:      "cafe",
   414  					ResourceNamespace: "default",
   415  				},
   416  				Name: "vs_default_cafe_tea-latest",
   417  				Servers: []version2.UpstreamServer{
   418  					{
   419  						Address: "10.0.0.30:80",
   420  					},
   421  				},
   422  				Keepalive: 16,
   423  			},
   424  			{
   425  				UpstreamLabels: version2.UpstreamLabels{
   426  					Service:           "coffee-svc",
   427  					ResourceType:      "virtualserver",
   428  					ResourceName:      "cafe",
   429  					ResourceNamespace: "default",
   430  				},
   431  				Name: "vs_default_cafe_coffee",
   432  				Servers: []version2.UpstreamServer{
   433  					{
   434  						Address: "10.0.0.40:80",
   435  					},
   436  				},
   437  				Keepalive: 16,
   438  			},
   439  			{
   440  				UpstreamLabels: version2.UpstreamLabels{
   441  					Service:           "coffee-svc",
   442  					ResourceType:      "virtualserverroute",
   443  					ResourceName:      "coffee",
   444  					ResourceNamespace: "default",
   445  				},
   446  				Name: "vs_default_cafe_vsr_default_coffee_coffee",
   447  				Servers: []version2.UpstreamServer{
   448  					{
   449  						Address: "10.0.0.40:80",
   450  					},
   451  				},
   452  				Keepalive: 16,
   453  			},
   454  			{
   455  				UpstreamLabels: version2.UpstreamLabels{
   456  					Service:           "sub-tea-svc",
   457  					ResourceType:      "virtualserverroute",
   458  					ResourceName:      "subtea",
   459  					ResourceNamespace: "default",
   460  				},
   461  				Name: "vs_default_cafe_vsr_default_subtea_subtea",
   462  				Servers: []version2.UpstreamServer{
   463  					{
   464  						Address: "10.0.0.50:80",
   465  					},
   466  				},
   467  				Keepalive: 16,
   468  			},
   469  			{
   470  				UpstreamLabels: version2.UpstreamLabels{
   471  					Service:           "coffee-svc",
   472  					ResourceType:      "virtualserverroute",
   473  					ResourceName:      "subcoffee",
   474  					ResourceNamespace: "default",
   475  				},
   476  				Name: "vs_default_cafe_vsr_default_subcoffee_coffee",
   477  				Servers: []version2.UpstreamServer{
   478  					{
   479  						Address: "10.0.0.40:80",
   480  					},
   481  				},
   482  				Keepalive: 16,
   483  			},
   484  		},
   485  		HTTPSnippets:  []string{},
   486  		LimitReqZones: []version2.LimitReqZone{},
   487  		Server: version2.Server{
   488  			ServerName:      "cafe.example.com",
   489  			StatusZone:      "cafe.example.com",
   490  			VSNamespace:     "default",
   491  			VSName:          "cafe",
   492  			ProxyProtocol:   true,
   493  			ServerTokens:    "off",
   494  			SetRealIPFrom:   []string{"0.0.0.0/0"},
   495  			RealIPHeader:    "X-Real-IP",
   496  			RealIPRecursive: true,
   497  			Snippets:        []string{"# server snippet"},
   498  			TLSPassthrough:  true,
   499  			Locations: []version2.Location{
   500  				{
   501  					Path:                     "/tea",
   502  					ProxyPass:                "http://vs_default_cafe_tea",
   503  					ProxyNextUpstream:        "error timeout",
   504  					ProxyNextUpstreamTimeout: "0s",
   505  					ProxyNextUpstreamTries:   0,
   506  					HasKeepalive:             true,
   507  					ProxySSLName:             "tea-svc.default.svc",
   508  					ProxyPassRequestHeaders:  true,
   509  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   510  					ServiceName:              "tea-svc",
   511  				},
   512  				{
   513  					Path:                     "/tea-latest",
   514  					ProxyPass:                "http://vs_default_cafe_tea-latest",
   515  					ProxyNextUpstream:        "error timeout",
   516  					ProxyNextUpstreamTimeout: "0s",
   517  					ProxyNextUpstreamTries:   0,
   518  					HasKeepalive:             true,
   519  					ProxySSLName:             "tea-svc.default.svc",
   520  					ProxyPassRequestHeaders:  true,
   521  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   522  					ServiceName:              "tea-svc",
   523  				},
   524  				// Order changes here because we generate first all the VS Routes and then all the VSR Subroutes (separated for loops)
   525  				{
   526  					Path:                     "/coffee-errorpage",
   527  					ProxyPass:                "http://vs_default_cafe_coffee",
   528  					ProxyNextUpstream:        "error timeout",
   529  					ProxyNextUpstreamTimeout: "0s",
   530  					ProxyNextUpstreamTries:   0,
   531  					HasKeepalive:             true,
   532  					ProxyInterceptErrors:     true,
   533  					ErrorPages: []version2.ErrorPage{
   534  						{
   535  							Name:         "http://nginx.com",
   536  							Codes:        "401 403",
   537  							ResponseCode: 301,
   538  						},
   539  					},
   540  					ProxySSLName:            "coffee-svc.default.svc",
   541  					ProxyPassRequestHeaders: true,
   542  					ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
   543  					ServiceName:             "coffee-svc",
   544  				},
   545  				{
   546  					Path:                     "/coffee",
   547  					ProxyPass:                "http://vs_default_cafe_vsr_default_coffee_coffee",
   548  					ProxyNextUpstream:        "error timeout",
   549  					ProxyNextUpstreamTimeout: "0s",
   550  					ProxyNextUpstreamTries:   0,
   551  					HasKeepalive:             true,
   552  					ProxySSLName:             "coffee-svc.default.svc",
   553  					ProxyPassRequestHeaders:  true,
   554  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   555  					ServiceName:              "coffee-svc",
   556  					IsVSR:                    true,
   557  					VSRName:                  "coffee",
   558  					VSRNamespace:             "default",
   559  				},
   560  				{
   561  					Path:                     "/subtea",
   562  					ProxyPass:                "http://vs_default_cafe_vsr_default_subtea_subtea",
   563  					ProxyNextUpstream:        "error timeout",
   564  					ProxyNextUpstreamTimeout: "0s",
   565  					ProxyNextUpstreamTries:   0,
   566  					HasKeepalive:             true,
   567  					ProxySSLName:             "sub-tea-svc.default.svc",
   568  					ProxyPassRequestHeaders:  true,
   569  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   570  					ServiceName:              "sub-tea-svc",
   571  					IsVSR:                    true,
   572  					VSRName:                  "subtea",
   573  					VSRNamespace:             "default",
   574  				},
   575  
   576  				{
   577  					Path:                     "/coffee-errorpage-subroute",
   578  					ProxyPass:                "http://vs_default_cafe_vsr_default_subcoffee_coffee",
   579  					ProxyNextUpstream:        "error timeout",
   580  					ProxyNextUpstreamTimeout: "0s",
   581  					ProxyNextUpstreamTries:   0,
   582  					HasKeepalive:             true,
   583  					ProxyInterceptErrors:     true,
   584  					ErrorPages: []version2.ErrorPage{
   585  						{
   586  							Name:         "http://nginx.com",
   587  							Codes:        "401 403",
   588  							ResponseCode: 301,
   589  						},
   590  					},
   591  					ProxySSLName:            "coffee-svc.default.svc",
   592  					ProxyPassRequestHeaders: true,
   593  					ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
   594  					ServiceName:             "coffee-svc",
   595  					IsVSR:                   true,
   596  					VSRName:                 "subcoffee",
   597  					VSRNamespace:            "default",
   598  				},
   599  				{
   600  					Path:                     "/coffee-errorpage-subroute-defined",
   601  					ProxyPass:                "http://vs_default_cafe_vsr_default_subcoffee_coffee",
   602  					ProxyNextUpstream:        "error timeout",
   603  					ProxyNextUpstreamTimeout: "0s",
   604  					ProxyNextUpstreamTries:   0,
   605  					HasKeepalive:             true,
   606  					ProxyInterceptErrors:     true,
   607  					ErrorPages: []version2.ErrorPage{
   608  						{
   609  							Name:         "@error_page_0_0",
   610  							Codes:        "502 503",
   611  							ResponseCode: 200,
   612  						},
   613  					},
   614  					ProxySSLName:            "coffee-svc.default.svc",
   615  					ProxyPassRequestHeaders: true,
   616  					ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
   617  					ServiceName:             "coffee-svc",
   618  					IsVSR:                   true,
   619  					VSRName:                 "subcoffee",
   620  					VSRNamespace:            "default",
   621  				},
   622  			},
   623  			ErrorPageLocations: []version2.ErrorPageLocation{
   624  				{
   625  					Name:        "@error_page_0_0",
   626  					DefaultType: "text/plain",
   627  					Return: &version2.Return{
   628  						Text: "All Good",
   629  					},
   630  				},
   631  			},
   632  		},
   633  	}
   634  
   635  	isPlus := false
   636  	isResolverConfigured := false
   637  	vsc := newVirtualServerConfigurator(
   638  		&baseCfgParams,
   639  		isPlus,
   640  		isResolverConfigured,
   641  		&StaticConfigParams{TLSPassthrough: true},
   642  	)
   643  
   644  	result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil)
   645  	if diff := cmp.Diff(expected, result); diff != "" {
   646  		t.Errorf("GenerateVirtualServerConfig() mismatch (-want +got):\n%s", diff)
   647  	}
   648  
   649  	if len(warnings) != 0 {
   650  		t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
   651  	}
   652  }
   653  
   654  func TestGenerateVirtualServerConfigWithSpiffeCerts(t *testing.T) {
   655  	virtualServerEx := VirtualServerEx{
   656  		VirtualServer: &conf_v1.VirtualServer{
   657  			ObjectMeta: meta_v1.ObjectMeta{
   658  				Name:      "cafe",
   659  				Namespace: "default",
   660  			},
   661  			Spec: conf_v1.VirtualServerSpec{
   662  				Host: "cafe.example.com",
   663  				Upstreams: []conf_v1.Upstream{
   664  					{
   665  						Name:    "tea",
   666  						Service: "tea-svc",
   667  						Port:    80,
   668  					},
   669  				},
   670  				Routes: []conf_v1.Route{
   671  					{
   672  						Path: "/tea",
   673  						Action: &conf_v1.Action{
   674  							Pass: "tea",
   675  						},
   676  					},
   677  				},
   678  			},
   679  		},
   680  		Endpoints: map[string][]string{
   681  			"default/tea-svc:80": {
   682  				"10.0.0.20:80",
   683  			},
   684  		},
   685  	}
   686  
   687  	baseCfgParams := ConfigParams{
   688  		ServerTokens:    "off",
   689  		Keepalive:       16,
   690  		ServerSnippets:  []string{"# server snippet"},
   691  		ProxyProtocol:   true,
   692  		SetRealIPFrom:   []string{"0.0.0.0/0"},
   693  		RealIPHeader:    "X-Real-IP",
   694  		RealIPRecursive: true,
   695  	}
   696  
   697  	expected := version2.VirtualServerConfig{
   698  		Upstreams: []version2.Upstream{
   699  			{
   700  				UpstreamLabels: version2.UpstreamLabels{
   701  					Service:           "tea-svc",
   702  					ResourceType:      "virtualserver",
   703  					ResourceName:      "cafe",
   704  					ResourceNamespace: "default",
   705  				},
   706  				Name: "vs_default_cafe_tea",
   707  				Servers: []version2.UpstreamServer{
   708  					{
   709  						Address: "10.0.0.20:80",
   710  					},
   711  				},
   712  				Keepalive: 16,
   713  			},
   714  		},
   715  		HTTPSnippets:  []string{},
   716  		LimitReqZones: []version2.LimitReqZone{},
   717  		Server: version2.Server{
   718  			ServerName:      "cafe.example.com",
   719  			StatusZone:      "cafe.example.com",
   720  			VSNamespace:     "default",
   721  			VSName:          "cafe",
   722  			ProxyProtocol:   true,
   723  			ServerTokens:    "off",
   724  			SetRealIPFrom:   []string{"0.0.0.0/0"},
   725  			RealIPHeader:    "X-Real-IP",
   726  			RealIPRecursive: true,
   727  			Snippets:        []string{"# server snippet"},
   728  			TLSPassthrough:  true,
   729  			Locations: []version2.Location{
   730  				{
   731  					Path:                     "/tea",
   732  					ProxyPass:                "https://vs_default_cafe_tea",
   733  					ProxyNextUpstream:        "error timeout",
   734  					ProxyNextUpstreamTimeout: "0s",
   735  					ProxyNextUpstreamTries:   0,
   736  					HasKeepalive:             true,
   737  					ProxySSLName:             "tea-svc.default.svc",
   738  					ProxyPassRequestHeaders:  true,
   739  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   740  					ServiceName:              "tea-svc",
   741  				},
   742  			},
   743  		},
   744  		SpiffeCerts: true,
   745  	}
   746  
   747  	isPlus := false
   748  	isResolverConfigured := false
   749  	staticConfigParams := &StaticConfigParams{TLSPassthrough: true, NginxServiceMesh: true}
   750  	vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, staticConfigParams)
   751  
   752  	result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil)
   753  	if diff := cmp.Diff(expected, result); diff != "" {
   754  		t.Errorf("GenerateVirtualServerConfig() mismatch (-want +got):\n%s", diff)
   755  	}
   756  
   757  	if len(warnings) != 0 {
   758  		t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
   759  	}
   760  }
   761  
   762  func TestGenerateVirtualServerConfigForVirtualServerWithSplits(t *testing.T) {
   763  	virtualServerEx := VirtualServerEx{
   764  		VirtualServer: &conf_v1.VirtualServer{
   765  			ObjectMeta: meta_v1.ObjectMeta{
   766  				Name:      "cafe",
   767  				Namespace: "default",
   768  			},
   769  			Spec: conf_v1.VirtualServerSpec{
   770  				Host: "cafe.example.com",
   771  				Upstreams: []conf_v1.Upstream{
   772  					{
   773  						Name:    "tea-v1",
   774  						Service: "tea-svc-v1",
   775  						Port:    80,
   776  					},
   777  					{
   778  						Name:    "tea-v2",
   779  						Service: "tea-svc-v2",
   780  						Port:    80,
   781  					},
   782  				},
   783  				Routes: []conf_v1.Route{
   784  					{
   785  						Path: "/tea",
   786  						Splits: []conf_v1.Split{
   787  							{
   788  								Weight: 90,
   789  								Action: &conf_v1.Action{
   790  									Pass: "tea-v1",
   791  								},
   792  							},
   793  							{
   794  								Weight: 10,
   795  								Action: &conf_v1.Action{
   796  									Pass: "tea-v2",
   797  								},
   798  							},
   799  						},
   800  					},
   801  					{
   802  						Path:  "/coffee",
   803  						Route: "default/coffee",
   804  					},
   805  				},
   806  			},
   807  		},
   808  		Endpoints: map[string][]string{
   809  			"default/tea-svc-v1:80": {
   810  				"10.0.0.20:80",
   811  			},
   812  			"default/tea-svc-v2:80": {
   813  				"10.0.0.21:80",
   814  			},
   815  			"default/coffee-svc-v1:80": {
   816  				"10.0.0.30:80",
   817  			},
   818  			"default/coffee-svc-v2:80": {
   819  				"10.0.0.31:80",
   820  			},
   821  		},
   822  		VirtualServerRoutes: []*conf_v1.VirtualServerRoute{
   823  			{
   824  				ObjectMeta: meta_v1.ObjectMeta{
   825  					Name:      "coffee",
   826  					Namespace: "default",
   827  				},
   828  				Spec: conf_v1.VirtualServerRouteSpec{
   829  					Host: "cafe.example.com",
   830  					Upstreams: []conf_v1.Upstream{
   831  						{
   832  							Name:    "coffee-v1",
   833  							Service: "coffee-svc-v1",
   834  							Port:    80,
   835  						},
   836  						{
   837  							Name:    "coffee-v2",
   838  							Service: "coffee-svc-v2",
   839  							Port:    80,
   840  						},
   841  					},
   842  					Subroutes: []conf_v1.Route{
   843  						{
   844  							Path: "/coffee",
   845  							Splits: []conf_v1.Split{
   846  								{
   847  									Weight: 40,
   848  									Action: &conf_v1.Action{
   849  										Pass: "coffee-v1",
   850  									},
   851  								},
   852  								{
   853  									Weight: 60,
   854  									Action: &conf_v1.Action{
   855  										Pass: "coffee-v2",
   856  									},
   857  								},
   858  							},
   859  						},
   860  					},
   861  				},
   862  			},
   863  		},
   864  	}
   865  
   866  	baseCfgParams := ConfigParams{}
   867  
   868  	expected := version2.VirtualServerConfig{
   869  		Upstreams: []version2.Upstream{
   870  			{
   871  				Name: "vs_default_cafe_tea-v1",
   872  				UpstreamLabels: version2.UpstreamLabels{
   873  					Service:           "tea-svc-v1",
   874  					ResourceType:      "virtualserver",
   875  					ResourceName:      "cafe",
   876  					ResourceNamespace: "default",
   877  				},
   878  				Servers: []version2.UpstreamServer{
   879  					{
   880  						Address: "10.0.0.20:80",
   881  					},
   882  				},
   883  			},
   884  			{
   885  				Name: "vs_default_cafe_tea-v2",
   886  				UpstreamLabels: version2.UpstreamLabels{
   887  					Service:           "tea-svc-v2",
   888  					ResourceType:      "virtualserver",
   889  					ResourceName:      "cafe",
   890  					ResourceNamespace: "default",
   891  				},
   892  				Servers: []version2.UpstreamServer{
   893  					{
   894  						Address: "10.0.0.21:80",
   895  					},
   896  				},
   897  			},
   898  			{
   899  				Name: "vs_default_cafe_vsr_default_coffee_coffee-v1",
   900  				UpstreamLabels: version2.UpstreamLabels{
   901  					Service:           "coffee-svc-v1",
   902  					ResourceType:      "virtualserverroute",
   903  					ResourceName:      "coffee",
   904  					ResourceNamespace: "default",
   905  				},
   906  				Servers: []version2.UpstreamServer{
   907  					{
   908  						Address: "10.0.0.30:80",
   909  					},
   910  				},
   911  			},
   912  			{
   913  				Name: "vs_default_cafe_vsr_default_coffee_coffee-v2",
   914  				UpstreamLabels: version2.UpstreamLabels{
   915  					Service:           "coffee-svc-v2",
   916  					ResourceType:      "virtualserverroute",
   917  					ResourceName:      "coffee",
   918  					ResourceNamespace: "default",
   919  				},
   920  				Servers: []version2.UpstreamServer{
   921  					{
   922  						Address: "10.0.0.31:80",
   923  					},
   924  				},
   925  			},
   926  		},
   927  		SplitClients: []version2.SplitClient{
   928  			{
   929  				Source:   "$request_id",
   930  				Variable: "$vs_default_cafe_splits_0",
   931  				Distributions: []version2.Distribution{
   932  					{
   933  						Weight: "90%",
   934  						Value:  "/internal_location_splits_0_split_0",
   935  					},
   936  					{
   937  						Weight: "10%",
   938  						Value:  "/internal_location_splits_0_split_1",
   939  					},
   940  				},
   941  			},
   942  			{
   943  				Source:   "$request_id",
   944  				Variable: "$vs_default_cafe_splits_1",
   945  				Distributions: []version2.Distribution{
   946  					{
   947  						Weight: "40%",
   948  						Value:  "/internal_location_splits_1_split_0",
   949  					},
   950  					{
   951  						Weight: "60%",
   952  						Value:  "/internal_location_splits_1_split_1",
   953  					},
   954  				},
   955  			},
   956  		},
   957  		HTTPSnippets:  []string{},
   958  		LimitReqZones: []version2.LimitReqZone{},
   959  		Server: version2.Server{
   960  			ServerName:  "cafe.example.com",
   961  			StatusZone:  "cafe.example.com",
   962  			VSNamespace: "default",
   963  			VSName:      "cafe",
   964  			InternalRedirectLocations: []version2.InternalRedirectLocation{
   965  				{
   966  					Path:        "/tea",
   967  					Destination: "$vs_default_cafe_splits_0",
   968  				},
   969  				{
   970  					Path:        "/coffee",
   971  					Destination: "$vs_default_cafe_splits_1",
   972  				},
   973  			},
   974  			Locations: []version2.Location{
   975  				{
   976  					Path:                     "/internal_location_splits_0_split_0",
   977  					ProxyPass:                "http://vs_default_cafe_tea-v1$request_uri",
   978  					ProxyNextUpstream:        "error timeout",
   979  					ProxyNextUpstreamTimeout: "0s",
   980  					ProxyNextUpstreamTries:   0,
   981  					Internal:                 true,
   982  					ProxySSLName:             "tea-svc-v1.default.svc",
   983  					ProxyPassRequestHeaders:  true,
   984  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   985  					ServiceName:              "tea-svc-v1",
   986  				},
   987  				{
   988  					Path:                     "/internal_location_splits_0_split_1",
   989  					ProxyPass:                "http://vs_default_cafe_tea-v2$request_uri",
   990  					ProxyNextUpstream:        "error timeout",
   991  					ProxyNextUpstreamTimeout: "0s",
   992  					ProxyNextUpstreamTries:   0,
   993  					Internal:                 true,
   994  					ProxySSLName:             "tea-svc-v2.default.svc",
   995  					ProxyPassRequestHeaders:  true,
   996  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
   997  					ServiceName:              "tea-svc-v2",
   998  				},
   999  				{
  1000  					Path:                     "/internal_location_splits_1_split_0",
  1001  					ProxyPass:                "http://vs_default_cafe_vsr_default_coffee_coffee-v1$request_uri",
  1002  					ProxyNextUpstream:        "error timeout",
  1003  					ProxyNextUpstreamTimeout: "0s",
  1004  					ProxyNextUpstreamTries:   0,
  1005  					Internal:                 true,
  1006  					ProxySSLName:             "coffee-svc-v1.default.svc",
  1007  					ProxyPassRequestHeaders:  true,
  1008  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1009  					ServiceName:              "coffee-svc-v1",
  1010  					IsVSR:                    true,
  1011  					VSRName:                  "coffee",
  1012  					VSRNamespace:             "default",
  1013  				},
  1014  				{
  1015  					Path:                     "/internal_location_splits_1_split_1",
  1016  					ProxyPass:                "http://vs_default_cafe_vsr_default_coffee_coffee-v2$request_uri",
  1017  					ProxyNextUpstream:        "error timeout",
  1018  					ProxyNextUpstreamTimeout: "0s",
  1019  					ProxyNextUpstreamTries:   0,
  1020  					Internal:                 true,
  1021  					ProxySSLName:             "coffee-svc-v2.default.svc",
  1022  					ProxyPassRequestHeaders:  true,
  1023  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1024  					ServiceName:              "coffee-svc-v2",
  1025  					IsVSR:                    true,
  1026  					VSRName:                  "coffee",
  1027  					VSRNamespace:             "default",
  1028  				},
  1029  			},
  1030  		},
  1031  	}
  1032  
  1033  	isPlus := false
  1034  	isResolverConfigured := false
  1035  	vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, &StaticConfigParams{})
  1036  
  1037  	result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil)
  1038  	if diff := cmp.Diff(expected, result); diff != "" {
  1039  		t.Errorf("GenerateVirtualServerConfig() mismatch (-want +got):\n%s", diff)
  1040  	}
  1041  
  1042  	if len(warnings) != 0 {
  1043  		t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
  1044  	}
  1045  }
  1046  
  1047  func TestGenerateVirtualServerConfigForVirtualServerWithMatches(t *testing.T) {
  1048  	virtualServerEx := VirtualServerEx{
  1049  		VirtualServer: &conf_v1.VirtualServer{
  1050  			ObjectMeta: meta_v1.ObjectMeta{
  1051  				Name:      "cafe",
  1052  				Namespace: "default",
  1053  			},
  1054  			Spec: conf_v1.VirtualServerSpec{
  1055  				Host: "cafe.example.com",
  1056  				Upstreams: []conf_v1.Upstream{
  1057  					{
  1058  						Name:    "tea-v1",
  1059  						Service: "tea-svc-v1",
  1060  						Port:    80,
  1061  					},
  1062  					{
  1063  						Name:    "tea-v2",
  1064  						Service: "tea-svc-v2",
  1065  						Port:    80,
  1066  					},
  1067  				},
  1068  				Routes: []conf_v1.Route{
  1069  					{
  1070  						Path: "/tea",
  1071  						Matches: []conf_v1.Match{
  1072  							{
  1073  								Conditions: []conf_v1.Condition{
  1074  									{
  1075  										Header: "x-version",
  1076  										Value:  "v2",
  1077  									},
  1078  								},
  1079  								Action: &conf_v1.Action{
  1080  									Pass: "tea-v2",
  1081  								},
  1082  							},
  1083  						},
  1084  						Action: &conf_v1.Action{
  1085  							Pass: "tea-v1",
  1086  						},
  1087  					},
  1088  					{
  1089  						Path:  "/coffee",
  1090  						Route: "default/coffee",
  1091  					},
  1092  				},
  1093  			},
  1094  		},
  1095  		Endpoints: map[string][]string{
  1096  			"default/tea-svc-v1:80": {
  1097  				"10.0.0.20:80",
  1098  			},
  1099  			"default/tea-svc-v2:80": {
  1100  				"10.0.0.21:80",
  1101  			},
  1102  			"default/coffee-svc-v1:80": {
  1103  				"10.0.0.30:80",
  1104  			},
  1105  			"default/coffee-svc-v2:80": {
  1106  				"10.0.0.31:80",
  1107  			},
  1108  		},
  1109  		VirtualServerRoutes: []*conf_v1.VirtualServerRoute{
  1110  			{
  1111  				ObjectMeta: meta_v1.ObjectMeta{
  1112  					Name:      "coffee",
  1113  					Namespace: "default",
  1114  				},
  1115  				Spec: conf_v1.VirtualServerRouteSpec{
  1116  					Host: "cafe.example.com",
  1117  					Upstreams: []conf_v1.Upstream{
  1118  						{
  1119  							Name:    "coffee-v1",
  1120  							Service: "coffee-svc-v1",
  1121  							Port:    80,
  1122  						},
  1123  						{
  1124  							Name:    "coffee-v2",
  1125  							Service: "coffee-svc-v2",
  1126  							Port:    80,
  1127  						},
  1128  					},
  1129  					Subroutes: []conf_v1.Route{
  1130  						{
  1131  							Path: "/coffee",
  1132  							Matches: []conf_v1.Match{
  1133  								{
  1134  									Conditions: []conf_v1.Condition{
  1135  										{
  1136  											Argument: "version",
  1137  											Value:    "v2",
  1138  										},
  1139  									},
  1140  									Action: &conf_v1.Action{
  1141  										Pass: "coffee-v2",
  1142  									},
  1143  								},
  1144  							},
  1145  							Action: &conf_v1.Action{
  1146  								Pass: "coffee-v1",
  1147  							},
  1148  						},
  1149  					},
  1150  				},
  1151  			},
  1152  		},
  1153  	}
  1154  
  1155  	baseCfgParams := ConfigParams{}
  1156  
  1157  	expected := version2.VirtualServerConfig{
  1158  		Upstreams: []version2.Upstream{
  1159  			{
  1160  				UpstreamLabels: version2.UpstreamLabels{
  1161  					Service:           "tea-svc-v1",
  1162  					ResourceType:      "virtualserver",
  1163  					ResourceName:      "cafe",
  1164  					ResourceNamespace: "default",
  1165  				},
  1166  				Name: "vs_default_cafe_tea-v1",
  1167  				Servers: []version2.UpstreamServer{
  1168  					{
  1169  						Address: "10.0.0.20:80",
  1170  					},
  1171  				},
  1172  			},
  1173  			{
  1174  				Name: "vs_default_cafe_tea-v2",
  1175  				UpstreamLabels: version2.UpstreamLabels{
  1176  					Service:           "tea-svc-v2",
  1177  					ResourceType:      "virtualserver",
  1178  					ResourceName:      "cafe",
  1179  					ResourceNamespace: "default",
  1180  				},
  1181  				Servers: []version2.UpstreamServer{
  1182  					{
  1183  						Address: "10.0.0.21:80",
  1184  					},
  1185  				},
  1186  			},
  1187  			{
  1188  				Name: "vs_default_cafe_vsr_default_coffee_coffee-v1",
  1189  				UpstreamLabels: version2.UpstreamLabels{
  1190  					Service:           "coffee-svc-v1",
  1191  					ResourceType:      "virtualserverroute",
  1192  					ResourceName:      "coffee",
  1193  					ResourceNamespace: "default",
  1194  				},
  1195  				Servers: []version2.UpstreamServer{
  1196  					{
  1197  						Address: "10.0.0.30:80",
  1198  					},
  1199  				},
  1200  			},
  1201  			{
  1202  				Name: "vs_default_cafe_vsr_default_coffee_coffee-v2",
  1203  				UpstreamLabels: version2.UpstreamLabels{
  1204  					Service:           "coffee-svc-v2",
  1205  					ResourceType:      "virtualserverroute",
  1206  					ResourceName:      "coffee",
  1207  					ResourceNamespace: "default",
  1208  				},
  1209  				Servers: []version2.UpstreamServer{
  1210  					{
  1211  						Address: "10.0.0.31:80",
  1212  					},
  1213  				},
  1214  			},
  1215  		},
  1216  		Maps: []version2.Map{
  1217  			{
  1218  				Source:   "$http_x_version",
  1219  				Variable: "$vs_default_cafe_matches_0_match_0_cond_0",
  1220  				Parameters: []version2.Parameter{
  1221  					{
  1222  						Value:  `"v2"`,
  1223  						Result: "1",
  1224  					},
  1225  					{
  1226  						Value:  "default",
  1227  						Result: "0",
  1228  					},
  1229  				},
  1230  			},
  1231  			{
  1232  				Source:   "$vs_default_cafe_matches_0_match_0_cond_0",
  1233  				Variable: "$vs_default_cafe_matches_0",
  1234  				Parameters: []version2.Parameter{
  1235  					{
  1236  						Value:  "~^1",
  1237  						Result: "/internal_location_matches_0_match_0",
  1238  					},
  1239  					{
  1240  						Value:  "default",
  1241  						Result: "/internal_location_matches_0_default",
  1242  					},
  1243  				},
  1244  			},
  1245  			{
  1246  				Source:   "$arg_version",
  1247  				Variable: "$vs_default_cafe_matches_1_match_0_cond_0",
  1248  				Parameters: []version2.Parameter{
  1249  					{
  1250  						Value:  `"v2"`,
  1251  						Result: "1",
  1252  					},
  1253  					{
  1254  						Value:  "default",
  1255  						Result: "0",
  1256  					},
  1257  				},
  1258  			},
  1259  			{
  1260  				Source:   "$vs_default_cafe_matches_1_match_0_cond_0",
  1261  				Variable: "$vs_default_cafe_matches_1",
  1262  				Parameters: []version2.Parameter{
  1263  					{
  1264  						Value:  "~^1",
  1265  						Result: "/internal_location_matches_1_match_0",
  1266  					},
  1267  					{
  1268  						Value:  "default",
  1269  						Result: "/internal_location_matches_1_default",
  1270  					},
  1271  				},
  1272  			},
  1273  		},
  1274  		HTTPSnippets:  []string{},
  1275  		LimitReqZones: []version2.LimitReqZone{},
  1276  		Server: version2.Server{
  1277  			ServerName:  "cafe.example.com",
  1278  			StatusZone:  "cafe.example.com",
  1279  			VSNamespace: "default",
  1280  			VSName:      "cafe",
  1281  			InternalRedirectLocations: []version2.InternalRedirectLocation{
  1282  				{
  1283  					Path:        "/tea",
  1284  					Destination: "$vs_default_cafe_matches_0",
  1285  				},
  1286  				{
  1287  					Path:        "/coffee",
  1288  					Destination: "$vs_default_cafe_matches_1",
  1289  				},
  1290  			},
  1291  			Locations: []version2.Location{
  1292  				{
  1293  					Path:                     "/internal_location_matches_0_match_0",
  1294  					ProxyPass:                "http://vs_default_cafe_tea-v2$request_uri",
  1295  					ProxyNextUpstream:        "error timeout",
  1296  					ProxyNextUpstreamTimeout: "0s",
  1297  					ProxyNextUpstreamTries:   0,
  1298  					Internal:                 true,
  1299  					ProxySSLName:             "tea-svc-v2.default.svc",
  1300  					ProxyPassRequestHeaders:  true,
  1301  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1302  					ServiceName:              "tea-svc-v2",
  1303  				},
  1304  				{
  1305  					Path:                     "/internal_location_matches_0_default",
  1306  					ProxyPass:                "http://vs_default_cafe_tea-v1$request_uri",
  1307  					ProxyNextUpstream:        "error timeout",
  1308  					ProxyNextUpstreamTimeout: "0s",
  1309  					ProxyNextUpstreamTries:   0,
  1310  					Internal:                 true,
  1311  					ProxySSLName:             "tea-svc-v1.default.svc",
  1312  					ProxyPassRequestHeaders:  true,
  1313  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1314  					ServiceName:              "tea-svc-v1",
  1315  				},
  1316  				{
  1317  					Path:                     "/internal_location_matches_1_match_0",
  1318  					ProxyPass:                "http://vs_default_cafe_vsr_default_coffee_coffee-v2$request_uri",
  1319  					ProxyNextUpstream:        "error timeout",
  1320  					ProxyNextUpstreamTimeout: "0s",
  1321  					ProxyNextUpstreamTries:   0,
  1322  					Internal:                 true,
  1323  					ProxySSLName:             "coffee-svc-v2.default.svc",
  1324  					ProxyPassRequestHeaders:  true,
  1325  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1326  					ServiceName:              "coffee-svc-v2",
  1327  					IsVSR:                    true,
  1328  					VSRName:                  "coffee",
  1329  					VSRNamespace:             "default",
  1330  				},
  1331  				{
  1332  					Path:                     "/internal_location_matches_1_default",
  1333  					ProxyPass:                "http://vs_default_cafe_vsr_default_coffee_coffee-v1$request_uri",
  1334  					ProxyNextUpstream:        "error timeout",
  1335  					ProxyNextUpstreamTimeout: "0s",
  1336  					ProxyNextUpstreamTries:   0,
  1337  					Internal:                 true,
  1338  					ProxySSLName:             "coffee-svc-v1.default.svc",
  1339  					ProxyPassRequestHeaders:  true,
  1340  					ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  1341  					ServiceName:              "coffee-svc-v1",
  1342  					IsVSR:                    true,
  1343  					VSRName:                  "coffee",
  1344  					VSRNamespace:             "default",
  1345  				},
  1346  			},
  1347  		},
  1348  	}
  1349  
  1350  	isPlus := false
  1351  	isResolverConfigured := false
  1352  	vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, &StaticConfigParams{})
  1353  
  1354  	result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil)
  1355  	if diff := cmp.Diff(expected, result); diff != "" {
  1356  		t.Errorf("GenerateVirtualServerConfig() mismatch (-want +got):\n%s", diff)
  1357  	}
  1358  
  1359  	if len(warnings) != 0 {
  1360  		t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
  1361  	}
  1362  }
  1363  
  1364  func TestGenerateVirtualServerConfigForVirtualServerWithReturns(t *testing.T) {
  1365  	virtualServerEx := VirtualServerEx{
  1366  		VirtualServer: &conf_v1.VirtualServer{
  1367  			ObjectMeta: meta_v1.ObjectMeta{
  1368  				Name:      "returns",
  1369  				Namespace: "default",
  1370  			},
  1371  			Spec: conf_v1.VirtualServerSpec{
  1372  				Host: "example.com",
  1373  				Routes: []conf_v1.Route{
  1374  					{
  1375  						Path: "/return",
  1376  						Action: &conf_v1.Action{
  1377  							Return: &conf_v1.ActionReturn{
  1378  								Body: "hello 0",
  1379  							},
  1380  						},
  1381  					},
  1382  					{
  1383  						Path: "/splits-with-return",
  1384  						Splits: []conf_v1.Split{
  1385  							{
  1386  								Weight: 90,
  1387  								Action: &conf_v1.Action{
  1388  									Return: &conf_v1.ActionReturn{
  1389  										Body: "hello 1",
  1390  									},
  1391  								},
  1392  							},
  1393  							{
  1394  								Weight: 10,
  1395  								Action: &conf_v1.Action{
  1396  									Return: &conf_v1.ActionReturn{
  1397  										Body: "hello 2",
  1398  									},
  1399  								},
  1400  							},
  1401  						},
  1402  					},
  1403  					{
  1404  						Path: "/matches-with-return",
  1405  						Matches: []conf_v1.Match{
  1406  							{
  1407  								Conditions: []conf_v1.Condition{
  1408  									{
  1409  										Header: "x-version",
  1410  										Value:  "v2",
  1411  									},
  1412  								},
  1413  								Action: &conf_v1.Action{
  1414  									Return: &conf_v1.ActionReturn{
  1415  										Body: "hello 3",
  1416  									},
  1417  								},
  1418  							},
  1419  						},
  1420  						Action: &conf_v1.Action{
  1421  							Return: &conf_v1.ActionReturn{
  1422  								Body: "hello 4",
  1423  							},
  1424  						},
  1425  					},
  1426  					{
  1427  						Path:  "/more",
  1428  						Route: "default/more-returns",
  1429  					},
  1430  				},
  1431  			},
  1432  		},
  1433  		VirtualServerRoutes: []*conf_v1.VirtualServerRoute{
  1434  			{
  1435  				ObjectMeta: meta_v1.ObjectMeta{
  1436  					Name:      "more-returns",
  1437  					Namespace: "default",
  1438  				},
  1439  				Spec: conf_v1.VirtualServerRouteSpec{
  1440  					Host: "example.com",
  1441  					Subroutes: []conf_v1.Route{
  1442  						{
  1443  							Path: "/more/return",
  1444  							Action: &conf_v1.Action{
  1445  								Return: &conf_v1.ActionReturn{
  1446  									Body: "hello 5",
  1447  								},
  1448  							},
  1449  						},
  1450  						{
  1451  							Path: "/more/splits-with-return",
  1452  							Splits: []conf_v1.Split{
  1453  								{
  1454  									Weight: 90,
  1455  									Action: &conf_v1.Action{
  1456  										Return: &conf_v1.ActionReturn{
  1457  											Body: "hello 6",
  1458  										},
  1459  									},
  1460  								},
  1461  								{
  1462  									Weight: 10,
  1463  									Action: &conf_v1.Action{
  1464  										Return: &conf_v1.ActionReturn{
  1465  											Body: "hello 7",
  1466  										},
  1467  									},
  1468  								},
  1469  							},
  1470  						},
  1471  						{
  1472  							Path: "/more/matches-with-return",
  1473  							Matches: []conf_v1.Match{
  1474  								{
  1475  									Conditions: []conf_v1.Condition{
  1476  										{
  1477  											Header: "x-version",
  1478  											Value:  "v2",
  1479  										},
  1480  									},
  1481  									Action: &conf_v1.Action{
  1482  										Return: &conf_v1.ActionReturn{
  1483  											Body: "hello 8",
  1484  										},
  1485  									},
  1486  								},
  1487  							},
  1488  							Action: &conf_v1.Action{
  1489  								Return: &conf_v1.ActionReturn{
  1490  									Body: "hello 9",
  1491  								},
  1492  							},
  1493  						},
  1494  					},
  1495  				},
  1496  			},
  1497  		},
  1498  	}
  1499  
  1500  	baseCfgParams := ConfigParams{}
  1501  
  1502  	expected := version2.VirtualServerConfig{
  1503  		Maps: []version2.Map{
  1504  			{
  1505  				Source:   "$http_x_version",
  1506  				Variable: "$vs_default_returns_matches_0_match_0_cond_0",
  1507  				Parameters: []version2.Parameter{
  1508  					{
  1509  						Value:  `"v2"`,
  1510  						Result: "1",
  1511  					},
  1512  					{
  1513  						Value:  "default",
  1514  						Result: "0",
  1515  					},
  1516  				},
  1517  			},
  1518  			{
  1519  				Source:   "$vs_default_returns_matches_0_match_0_cond_0",
  1520  				Variable: "$vs_default_returns_matches_0",
  1521  				Parameters: []version2.Parameter{
  1522  					{
  1523  						Value:  "~^1",
  1524  						Result: "/internal_location_matches_0_match_0",
  1525  					},
  1526  					{
  1527  						Value:  "default",
  1528  						Result: "/internal_location_matches_0_default",
  1529  					},
  1530  				},
  1531  			},
  1532  			{
  1533  				Source:   "$http_x_version",
  1534  				Variable: "$vs_default_returns_matches_1_match_0_cond_0",
  1535  				Parameters: []version2.Parameter{
  1536  					{
  1537  						Value:  `"v2"`,
  1538  						Result: "1",
  1539  					},
  1540  					{
  1541  						Value:  "default",
  1542  						Result: "0",
  1543  					},
  1544  				},
  1545  			},
  1546  			{
  1547  				Source:   "$vs_default_returns_matches_1_match_0_cond_0",
  1548  				Variable: "$vs_default_returns_matches_1",
  1549  				Parameters: []version2.Parameter{
  1550  					{
  1551  						Value:  "~^1",
  1552  						Result: "/internal_location_matches_1_match_0",
  1553  					},
  1554  					{
  1555  						Value:  "default",
  1556  						Result: "/internal_location_matches_1_default",
  1557  					},
  1558  				},
  1559  			},
  1560  		},
  1561  		SplitClients: []version2.SplitClient{
  1562  			{
  1563  				Source:   "$request_id",
  1564  				Variable: "$vs_default_returns_splits_0",
  1565  				Distributions: []version2.Distribution{
  1566  					{
  1567  						Weight: "90%",
  1568  						Value:  "/internal_location_splits_0_split_0",
  1569  					},
  1570  					{
  1571  						Weight: "10%",
  1572  						Value:  "/internal_location_splits_0_split_1",
  1573  					},
  1574  				},
  1575  			},
  1576  			{
  1577  				Source:   "$request_id",
  1578  				Variable: "$vs_default_returns_splits_1",
  1579  				Distributions: []version2.Distribution{
  1580  					{
  1581  						Weight: "90%",
  1582  						Value:  "/internal_location_splits_1_split_0",
  1583  					},
  1584  					{
  1585  						Weight: "10%",
  1586  						Value:  "/internal_location_splits_1_split_1",
  1587  					},
  1588  				},
  1589  			},
  1590  		},
  1591  		HTTPSnippets:  []string{},
  1592  		LimitReqZones: []version2.LimitReqZone{},
  1593  		Server: version2.Server{
  1594  			ServerName:  "example.com",
  1595  			StatusZone:  "example.com",
  1596  			VSNamespace: "default",
  1597  			VSName:      "returns",
  1598  			InternalRedirectLocations: []version2.InternalRedirectLocation{
  1599  				{
  1600  					Path:        "/splits-with-return",
  1601  					Destination: "$vs_default_returns_splits_0",
  1602  				},
  1603  				{
  1604  					Path:        "/matches-with-return",
  1605  					Destination: "$vs_default_returns_matches_0",
  1606  				},
  1607  				{
  1608  					Path:        "/more/splits-with-return",
  1609  					Destination: "$vs_default_returns_splits_1",
  1610  				},
  1611  				{
  1612  					Path:        "/more/matches-with-return",
  1613  					Destination: "$vs_default_returns_matches_1",
  1614  				},
  1615  			},
  1616  			ReturnLocations: []version2.ReturnLocation{
  1617  				{
  1618  					Name:        "@return_0",
  1619  					DefaultType: "text/plain",
  1620  					Return: version2.Return{
  1621  						Code: 0,
  1622  						Text: "hello 0",
  1623  					},
  1624  				},
  1625  				{
  1626  					Name:        "@return_1",
  1627  					DefaultType: "text/plain",
  1628  					Return: version2.Return{
  1629  						Code: 0,
  1630  						Text: "hello 1",
  1631  					},
  1632  				},
  1633  				{
  1634  					Name:        "@return_2",
  1635  					DefaultType: "text/plain",
  1636  					Return: version2.Return{
  1637  						Code: 0,
  1638  						Text: "hello 2",
  1639  					},
  1640  				},
  1641  				{
  1642  					Name:        "@return_3",
  1643  					DefaultType: "text/plain",
  1644  					Return: version2.Return{
  1645  						Code: 0,
  1646  						Text: "hello 3",
  1647  					},
  1648  				},
  1649  				{
  1650  					Name:        "@return_4",
  1651  					DefaultType: "text/plain",
  1652  					Return: version2.Return{
  1653  						Code: 0,
  1654  						Text: "hello 4",
  1655  					},
  1656  				},
  1657  				{
  1658  					Name:        "@return_5",
  1659  					DefaultType: "text/plain",
  1660  					Return: version2.Return{
  1661  						Code: 0,
  1662  						Text: "hello 5",
  1663  					},
  1664  				},
  1665  				{
  1666  					Name:        "@return_6",
  1667  					DefaultType: "text/plain",
  1668  					Return: version2.Return{
  1669  						Code: 0,
  1670  						Text: "hello 6",
  1671  					},
  1672  				},
  1673  				{
  1674  					Name:        "@return_7",
  1675  					DefaultType: "text/plain",
  1676  					Return: version2.Return{
  1677  						Code: 0,
  1678  						Text: "hello 7",
  1679  					},
  1680  				},
  1681  				{
  1682  					Name:        "@return_8",
  1683  					DefaultType: "text/plain",
  1684  					Return: version2.Return{
  1685  						Code: 0,
  1686  						Text: "hello 8",
  1687  					},
  1688  				},
  1689  				{
  1690  					Name:        "@return_9",
  1691  					DefaultType: "text/plain",
  1692  					Return: version2.Return{
  1693  						Code: 0,
  1694  						Text: "hello 9",
  1695  					},
  1696  				},
  1697  			},
  1698  			Locations: []version2.Location{
  1699  				{
  1700  					Path:                 "/return",
  1701  					ProxyInterceptErrors: true,
  1702  					ErrorPages: []version2.ErrorPage{
  1703  						{
  1704  							Name:         "@return_0",
  1705  							Codes:        "418",
  1706  							ResponseCode: 200,
  1707  						},
  1708  					},
  1709  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1710  				},
  1711  				{
  1712  					Path:                 "/internal_location_splits_0_split_0",
  1713  					ProxyInterceptErrors: true,
  1714  					ErrorPages: []version2.ErrorPage{
  1715  						{
  1716  							Name:         "@return_1",
  1717  							Codes:        "418",
  1718  							ResponseCode: 200,
  1719  						},
  1720  					},
  1721  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1722  				},
  1723  				{
  1724  					Path:                 "/internal_location_splits_0_split_1",
  1725  					ProxyInterceptErrors: true,
  1726  					ErrorPages: []version2.ErrorPage{
  1727  						{
  1728  							Name:         "@return_2",
  1729  							Codes:        "418",
  1730  							ResponseCode: 200,
  1731  						},
  1732  					},
  1733  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1734  				},
  1735  				{
  1736  					Path:                 "/internal_location_matches_0_match_0",
  1737  					ProxyInterceptErrors: true,
  1738  					ErrorPages: []version2.ErrorPage{
  1739  						{
  1740  							Name:         "@return_3",
  1741  							Codes:        "418",
  1742  							ResponseCode: 200,
  1743  						},
  1744  					},
  1745  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1746  				},
  1747  				{
  1748  					Path:                 "/internal_location_matches_0_default",
  1749  					ProxyInterceptErrors: true,
  1750  					ErrorPages: []version2.ErrorPage{
  1751  						{
  1752  							Name:         "@return_4",
  1753  							Codes:        "418",
  1754  							ResponseCode: 200,
  1755  						},
  1756  					},
  1757  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1758  				},
  1759  				{
  1760  					Path:                 "/more/return",
  1761  					ProxyInterceptErrors: true,
  1762  					ErrorPages: []version2.ErrorPage{
  1763  						{
  1764  							Name:         "@return_5",
  1765  							Codes:        "418",
  1766  							ResponseCode: 200,
  1767  						},
  1768  					},
  1769  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1770  				},
  1771  				{
  1772  					Path:                 "/internal_location_splits_1_split_0",
  1773  					ProxyInterceptErrors: true,
  1774  					ErrorPages: []version2.ErrorPage{
  1775  						{
  1776  							Name:         "@return_6",
  1777  							Codes:        "418",
  1778  							ResponseCode: 200,
  1779  						},
  1780  					},
  1781  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1782  				},
  1783  				{
  1784  					Path:                 "/internal_location_splits_1_split_1",
  1785  					ProxyInterceptErrors: true,
  1786  					ErrorPages: []version2.ErrorPage{
  1787  						{
  1788  							Name:         "@return_7",
  1789  							Codes:        "418",
  1790  							ResponseCode: 200,
  1791  						},
  1792  					},
  1793  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1794  				},
  1795  				{
  1796  					Path:                 "/internal_location_matches_1_match_0",
  1797  					ProxyInterceptErrors: true,
  1798  					ErrorPages: []version2.ErrorPage{
  1799  						{
  1800  							Name:         "@return_8",
  1801  							Codes:        "418",
  1802  							ResponseCode: 200,
  1803  						},
  1804  					},
  1805  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1806  				},
  1807  				{
  1808  					Path:                 "/internal_location_matches_1_default",
  1809  					ProxyInterceptErrors: true,
  1810  					ErrorPages: []version2.ErrorPage{
  1811  						{
  1812  							Name:         "@return_9",
  1813  							Codes:        "418",
  1814  							ResponseCode: 200,
  1815  						},
  1816  					},
  1817  					InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  1818  				},
  1819  			},
  1820  		},
  1821  	}
  1822  
  1823  	isPlus := false
  1824  	isResolverConfigured := false
  1825  	vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, &StaticConfigParams{})
  1826  
  1827  	result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil)
  1828  	if !reflect.DeepEqual(result, expected) {
  1829  		t.Errorf("GenerateVirtualServerConfig returned \n%+v but expected \n%+v", result, expected)
  1830  	}
  1831  
  1832  	if len(warnings) != 0 {
  1833  		t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
  1834  	}
  1835  }
  1836  
  1837  func TestGeneratePolicies(t *testing.T) {
  1838  	ownerDetails := policyOwnerDetails{
  1839  		owner:          nil, // nil is OK for the unit test
  1840  		ownerNamespace: "default",
  1841  		vsNamespace:    "default",
  1842  		vsName:         "test",
  1843  	}
  1844  	ingressMTLSCertPath := "/etc/nginx/secrets/default-ingress-mtls-secret"
  1845  	policyOpts := policyOptions{
  1846  		tls: true,
  1847  		secretRefs: map[string]*secrets.SecretReference{
  1848  			"default/ingress-mtls-secret": {
  1849  				Secret: &api_v1.Secret{
  1850  					Type: secrets.SecretTypeCA,
  1851  				},
  1852  				Path: ingressMTLSCertPath,
  1853  			},
  1854  			"default/egress-mtls-secret": {
  1855  				Secret: &api_v1.Secret{
  1856  					Type: api_v1.SecretTypeTLS,
  1857  				},
  1858  				Path: "/etc/nginx/secrets/default-egress-mtls-secret",
  1859  			},
  1860  			"default/egress-trusted-ca-secret": {
  1861  				Secret: &api_v1.Secret{
  1862  					Type: secrets.SecretTypeCA,
  1863  				},
  1864  				Path: "/etc/nginx/secrets/default-egress-trusted-ca-secret",
  1865  			},
  1866  			"default/jwt-secret": {
  1867  				Secret: &api_v1.Secret{
  1868  					Type: secrets.SecretTypeJWK,
  1869  				},
  1870  				Path: "/etc/nginx/secrets/default-jwt-secret",
  1871  			},
  1872  			"default/oidc-secret": {
  1873  				Secret: &api_v1.Secret{
  1874  					Type: secrets.SecretTypeOIDC,
  1875  					Data: map[string][]byte{
  1876  						"client-secret": []byte("super_secret_123"),
  1877  					},
  1878  				},
  1879  			},
  1880  		},
  1881  		apResources: map[string]string{
  1882  			"default/logconf":         "/etc/nginx/waf/nac-logconfs/default-logconf",
  1883  			"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  1884  		},
  1885  	}
  1886  
  1887  	tests := []struct {
  1888  		policyRefs []conf_v1.PolicyReference
  1889  		policies   map[string]*conf_v1.Policy
  1890  		policyOpts policyOptions
  1891  		context    string
  1892  		expected   policiesCfg
  1893  		msg        string
  1894  	}{
  1895  		{
  1896  			policyRefs: []conf_v1.PolicyReference{
  1897  				{
  1898  					Name:      "allow-policy",
  1899  					Namespace: "default",
  1900  				},
  1901  			},
  1902  			policies: map[string]*conf_v1.Policy{
  1903  				"default/allow-policy": {
  1904  					Spec: conf_v1.PolicySpec{
  1905  						AccessControl: &conf_v1.AccessControl{
  1906  							Allow: []string{"127.0.0.1"},
  1907  						},
  1908  					},
  1909  				},
  1910  			},
  1911  			expected: policiesCfg{
  1912  				Allow: []string{"127.0.0.1"},
  1913  			},
  1914  			msg: "explicit reference",
  1915  		},
  1916  		{
  1917  			policyRefs: []conf_v1.PolicyReference{
  1918  				{
  1919  					Name: "allow-policy",
  1920  				},
  1921  			},
  1922  			policies: map[string]*conf_v1.Policy{
  1923  				"default/allow-policy": {
  1924  					Spec: conf_v1.PolicySpec{
  1925  						AccessControl: &conf_v1.AccessControl{
  1926  							Allow: []string{"127.0.0.1"},
  1927  						},
  1928  					},
  1929  				},
  1930  			},
  1931  			expected: policiesCfg{
  1932  				Allow: []string{"127.0.0.1"},
  1933  			},
  1934  			msg: "implicit reference",
  1935  		},
  1936  		{
  1937  			policyRefs: []conf_v1.PolicyReference{
  1938  				{
  1939  					Name: "allow-policy-1",
  1940  				},
  1941  				{
  1942  					Name: "allow-policy-2",
  1943  				},
  1944  			},
  1945  			policies: map[string]*conf_v1.Policy{
  1946  				"default/allow-policy-1": {
  1947  					Spec: conf_v1.PolicySpec{
  1948  						AccessControl: &conf_v1.AccessControl{
  1949  							Allow: []string{"127.0.0.1"},
  1950  						},
  1951  					},
  1952  				},
  1953  				"default/allow-policy-2": {
  1954  					Spec: conf_v1.PolicySpec{
  1955  						AccessControl: &conf_v1.AccessControl{
  1956  							Allow: []string{"127.0.0.2"},
  1957  						},
  1958  					},
  1959  				},
  1960  			},
  1961  			expected: policiesCfg{
  1962  				Allow: []string{"127.0.0.1", "127.0.0.2"},
  1963  			},
  1964  			msg: "merging",
  1965  		},
  1966  		{
  1967  			policyRefs: []conf_v1.PolicyReference{
  1968  				{
  1969  					Name:      "rateLimit-policy",
  1970  					Namespace: "default",
  1971  				},
  1972  			},
  1973  			policies: map[string]*conf_v1.Policy{
  1974  				"default/rateLimit-policy": {
  1975  					Spec: conf_v1.PolicySpec{
  1976  						RateLimit: &conf_v1.RateLimit{
  1977  							Key:      "test",
  1978  							ZoneSize: "10M",
  1979  							Rate:     "10r/s",
  1980  							LogLevel: "notice",
  1981  						},
  1982  					},
  1983  				},
  1984  			},
  1985  			expected: policiesCfg{
  1986  				LimitReqZones: []version2.LimitReqZone{
  1987  					{
  1988  						Key:      "test",
  1989  						ZoneSize: "10M",
  1990  						Rate:     "10r/s",
  1991  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  1992  					},
  1993  				},
  1994  				LimitReqOptions: version2.LimitReqOptions{
  1995  					LogLevel:   "notice",
  1996  					RejectCode: 503,
  1997  				},
  1998  				LimitReqs: []version2.LimitReq{
  1999  					{
  2000  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  2001  					},
  2002  				},
  2003  			},
  2004  			msg: "rate limit reference",
  2005  		},
  2006  		{
  2007  			policyRefs: []conf_v1.PolicyReference{
  2008  				{
  2009  					Name:      "rateLimit-policy",
  2010  					Namespace: "default",
  2011  				},
  2012  				{
  2013  					Name:      "rateLimit-policy2",
  2014  					Namespace: "default",
  2015  				},
  2016  			},
  2017  			policies: map[string]*conf_v1.Policy{
  2018  				"default/rateLimit-policy": {
  2019  					Spec: conf_v1.PolicySpec{
  2020  						RateLimit: &conf_v1.RateLimit{
  2021  							Key:      "test",
  2022  							ZoneSize: "10M",
  2023  							Rate:     "10r/s",
  2024  						},
  2025  					},
  2026  				},
  2027  				"default/rateLimit-policy2": {
  2028  					Spec: conf_v1.PolicySpec{
  2029  						RateLimit: &conf_v1.RateLimit{
  2030  							Key:      "test2",
  2031  							ZoneSize: "20M",
  2032  							Rate:     "20r/s",
  2033  						},
  2034  					},
  2035  				},
  2036  			},
  2037  			expected: policiesCfg{
  2038  				LimitReqZones: []version2.LimitReqZone{
  2039  					{
  2040  						Key:      "test",
  2041  						ZoneSize: "10M",
  2042  						Rate:     "10r/s",
  2043  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  2044  					},
  2045  					{
  2046  						Key:      "test2",
  2047  						ZoneSize: "20M",
  2048  						Rate:     "20r/s",
  2049  						ZoneName: "pol_rl_default_rateLimit-policy2_default_test",
  2050  					},
  2051  				},
  2052  				LimitReqOptions: version2.LimitReqOptions{
  2053  					LogLevel:   "error",
  2054  					RejectCode: 503,
  2055  				},
  2056  				LimitReqs: []version2.LimitReq{
  2057  					{
  2058  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  2059  					},
  2060  					{
  2061  						ZoneName: "pol_rl_default_rateLimit-policy2_default_test",
  2062  					},
  2063  				},
  2064  			},
  2065  			msg: "multi rate limit reference",
  2066  		},
  2067  		{
  2068  			policyRefs: []conf_v1.PolicyReference{
  2069  				{
  2070  					Name:      "jwt-policy",
  2071  					Namespace: "default",
  2072  				},
  2073  			},
  2074  			policies: map[string]*conf_v1.Policy{
  2075  				"default/jwt-policy": {
  2076  					ObjectMeta: meta_v1.ObjectMeta{
  2077  						Name:      "jwt-policy",
  2078  						Namespace: "default",
  2079  					},
  2080  					Spec: conf_v1.PolicySpec{
  2081  						JWTAuth: &conf_v1.JWTAuth{
  2082  							Realm:  "My Test API",
  2083  							Secret: "jwt-secret",
  2084  						},
  2085  					},
  2086  				},
  2087  			},
  2088  			expected: policiesCfg{
  2089  				JWTAuth: &version2.JWTAuth{
  2090  					Secret: "/etc/nginx/secrets/default-jwt-secret",
  2091  					Realm:  "My Test API",
  2092  				},
  2093  			},
  2094  			msg: "jwt reference",
  2095  		},
  2096  		{
  2097  			policyRefs: []conf_v1.PolicyReference{
  2098  				{
  2099  					Name:      "ingress-mtls-policy",
  2100  					Namespace: "default",
  2101  				},
  2102  			},
  2103  			policies: map[string]*conf_v1.Policy{
  2104  				"default/ingress-mtls-policy": {
  2105  					ObjectMeta: meta_v1.ObjectMeta{
  2106  						Name:      "ingress-mtls-policy",
  2107  						Namespace: "default",
  2108  					},
  2109  					Spec: conf_v1.PolicySpec{
  2110  						IngressMTLS: &conf_v1.IngressMTLS{
  2111  							ClientCertSecret: "ingress-mtls-secret",
  2112  							VerifyClient:     "off",
  2113  						},
  2114  					},
  2115  				},
  2116  			},
  2117  			context: "spec",
  2118  			expected: policiesCfg{
  2119  				IngressMTLS: &version2.IngressMTLS{
  2120  					ClientCert:   ingressMTLSCertPath,
  2121  					VerifyClient: "off",
  2122  					VerifyDepth:  1,
  2123  				},
  2124  			},
  2125  			msg: "ingressMTLS reference",
  2126  		},
  2127  		{
  2128  			policyRefs: []conf_v1.PolicyReference{
  2129  				{
  2130  					Name:      "egress-mtls-policy",
  2131  					Namespace: "default",
  2132  				},
  2133  			},
  2134  			policies: map[string]*conf_v1.Policy{
  2135  				"default/egress-mtls-policy": {
  2136  					Spec: conf_v1.PolicySpec{
  2137  						EgressMTLS: &conf_v1.EgressMTLS{
  2138  							TLSSecret:         "egress-mtls-secret",
  2139  							ServerName:        true,
  2140  							SessionReuse:      createPointerFromBool(false),
  2141  							TrustedCertSecret: "egress-trusted-ca-secret",
  2142  						},
  2143  					},
  2144  				},
  2145  			},
  2146  			context: "route",
  2147  			expected: policiesCfg{
  2148  				EgressMTLS: &version2.EgressMTLS{
  2149  					Certificate:    "/etc/nginx/secrets/default-egress-mtls-secret",
  2150  					CertificateKey: "/etc/nginx/secrets/default-egress-mtls-secret",
  2151  					Ciphers:        "DEFAULT",
  2152  					Protocols:      "TLSv1 TLSv1.1 TLSv1.2",
  2153  					ServerName:     true,
  2154  					SessionReuse:   false,
  2155  					VerifyDepth:    1,
  2156  					VerifyServer:   false,
  2157  					TrustedCert:    "/etc/nginx/secrets/default-egress-trusted-ca-secret",
  2158  					SSLName:        "$proxy_host",
  2159  				},
  2160  			},
  2161  			msg: "egressMTLS reference",
  2162  		},
  2163  		{
  2164  			policyRefs: []conf_v1.PolicyReference{
  2165  				{
  2166  					Name:      "oidc-policy",
  2167  					Namespace: "default",
  2168  				},
  2169  			},
  2170  			policies: map[string]*conf_v1.Policy{
  2171  				"default/oidc-policy": {
  2172  					ObjectMeta: meta_v1.ObjectMeta{
  2173  						Name:      "oidc-policy",
  2174  						Namespace: "default",
  2175  					},
  2176  					Spec: conf_v1.PolicySpec{
  2177  						OIDC: &conf_v1.OIDC{
  2178  							AuthEndpoint:  "http://example.com/auth",
  2179  							TokenEndpoint: "http://example.com/token",
  2180  							JWKSURI:       "http://example.com/jwks",
  2181  							ClientID:      "client-id",
  2182  							ClientSecret:  "oidc-secret",
  2183  							Scope:         "scope",
  2184  							RedirectURI:   "/redirect",
  2185  						},
  2186  					},
  2187  				},
  2188  			},
  2189  			expected: policiesCfg{
  2190  				OIDC: true,
  2191  			},
  2192  			msg: "oidc reference",
  2193  		},
  2194  		{
  2195  			policyRefs: []conf_v1.PolicyReference{
  2196  				{
  2197  					Name:      "waf-policy",
  2198  					Namespace: "default",
  2199  				},
  2200  			},
  2201  			policies: map[string]*conf_v1.Policy{
  2202  				"default/waf-policy": {
  2203  					Spec: conf_v1.PolicySpec{
  2204  						WAF: &conf_v1.WAF{
  2205  							Enable:   true,
  2206  							ApPolicy: "default/dataguard-alarm",
  2207  							SecurityLog: &conf_v1.SecurityLog{
  2208  								Enable:    true,
  2209  								ApLogConf: "default/logconf",
  2210  								LogDest:   "syslog:server=127.0.0.1:514",
  2211  							},
  2212  						},
  2213  					},
  2214  				},
  2215  			},
  2216  			context: "route",
  2217  			expected: policiesCfg{
  2218  				WAF: &version2.WAF{
  2219  					Enable:              "on",
  2220  					ApPolicy:            "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  2221  					ApSecurityLogEnable: true,
  2222  					ApLogConf:           "/etc/nginx/waf/nac-logconfs/default-logconf syslog:server=127.0.0.1:514",
  2223  				},
  2224  			},
  2225  			msg: "WAF reference",
  2226  		},
  2227  	}
  2228  
  2229  	vsc := newVirtualServerConfigurator(&ConfigParams{}, false, false, &StaticConfigParams{})
  2230  
  2231  	for _, test := range tests {
  2232  		result := vsc.generatePolicies(ownerDetails, test.policyRefs, test.policies, test.context, policyOpts)
  2233  		if diff := cmp.Diff(test.expected, result); diff != "" {
  2234  			t.Errorf("generatePolicies() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  2235  		}
  2236  		if len(vsc.warnings) > 0 {
  2237  			t.Errorf("generatePolicies() returned unexpected warnings %v for the case of %s", vsc.warnings, test.msg)
  2238  		}
  2239  	}
  2240  }
  2241  
  2242  func TestGeneratePoliciesFails(t *testing.T) {
  2243  	ownerDetails := policyOwnerDetails{
  2244  		owner:          nil, // nil is OK for the unit test
  2245  		ownerNamespace: "default",
  2246  		vsNamespace:    "default",
  2247  		vsName:         "test",
  2248  	}
  2249  
  2250  	dryRunOverride := true
  2251  	rejectCodeOverride := 505
  2252  
  2253  	tests := []struct {
  2254  		policyRefs        []conf_v1.PolicyReference
  2255  		policies          map[string]*conf_v1.Policy
  2256  		policyOpts        policyOptions
  2257  		trustedCAFileName string
  2258  		context           string
  2259  		oidcPolCfg        *oidcPolicyCfg
  2260  		expected          policiesCfg
  2261  		expectedWarnings  Warnings
  2262  		expectedOidc      *oidcPolicyCfg
  2263  		msg               string
  2264  	}{
  2265  		{
  2266  			policyRefs: []conf_v1.PolicyReference{
  2267  				{
  2268  					Name:      "allow-policy",
  2269  					Namespace: "default",
  2270  				},
  2271  			},
  2272  			policies:   map[string]*conf_v1.Policy{},
  2273  			policyOpts: policyOptions{},
  2274  			expected: policiesCfg{
  2275  				ErrorReturn: &version2.Return{
  2276  					Code: 500,
  2277  				},
  2278  			},
  2279  			expectedWarnings: Warnings{
  2280  				nil: {
  2281  					"Policy default/allow-policy is missing or invalid",
  2282  				},
  2283  			},
  2284  			expectedOidc: &oidcPolicyCfg{},
  2285  			msg:          "missing policy",
  2286  		},
  2287  		{
  2288  			policyRefs: []conf_v1.PolicyReference{
  2289  				{
  2290  					Name: "allow-policy",
  2291  				},
  2292  				{
  2293  					Name: "deny-policy",
  2294  				},
  2295  			},
  2296  			policies: map[string]*conf_v1.Policy{
  2297  				"default/allow-policy": {
  2298  					Spec: conf_v1.PolicySpec{
  2299  						AccessControl: &conf_v1.AccessControl{
  2300  							Allow: []string{"127.0.0.1"},
  2301  						},
  2302  					},
  2303  				},
  2304  				"default/deny-policy": {
  2305  					Spec: conf_v1.PolicySpec{
  2306  						AccessControl: &conf_v1.AccessControl{
  2307  							Deny: []string{"127.0.0.2"},
  2308  						},
  2309  					},
  2310  				},
  2311  			},
  2312  			policyOpts: policyOptions{},
  2313  			expected: policiesCfg{
  2314  				Allow: []string{"127.0.0.1"},
  2315  				Deny:  []string{"127.0.0.2"},
  2316  			},
  2317  			expectedWarnings: Warnings{
  2318  				nil: {
  2319  					"AccessControl policy (or policies) with deny rules is overridden by policy (or policies) with allow rules",
  2320  				},
  2321  			},
  2322  			expectedOidc: &oidcPolicyCfg{},
  2323  			msg:          "conflicting policies",
  2324  		},
  2325  		{
  2326  			policyRefs: []conf_v1.PolicyReference{
  2327  				{
  2328  					Name:      "rateLimit-policy",
  2329  					Namespace: "default",
  2330  				},
  2331  				{
  2332  					Name:      "rateLimit-policy2",
  2333  					Namespace: "default",
  2334  				},
  2335  			},
  2336  			policies: map[string]*conf_v1.Policy{
  2337  				"default/rateLimit-policy": {
  2338  					Spec: conf_v1.PolicySpec{
  2339  						RateLimit: &conf_v1.RateLimit{
  2340  							Key:      "test",
  2341  							ZoneSize: "10M",
  2342  							Rate:     "10r/s",
  2343  						},
  2344  					},
  2345  				},
  2346  				"default/rateLimit-policy2": {
  2347  					Spec: conf_v1.PolicySpec{
  2348  						RateLimit: &conf_v1.RateLimit{
  2349  							Key:        "test2",
  2350  							ZoneSize:   "20M",
  2351  							Rate:       "20r/s",
  2352  							DryRun:     &dryRunOverride,
  2353  							LogLevel:   "info",
  2354  							RejectCode: &rejectCodeOverride,
  2355  						},
  2356  					},
  2357  				},
  2358  			},
  2359  			policyOpts: policyOptions{},
  2360  			expected: policiesCfg{
  2361  				LimitReqZones: []version2.LimitReqZone{
  2362  					{
  2363  						Key:      "test",
  2364  						ZoneSize: "10M",
  2365  						Rate:     "10r/s",
  2366  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  2367  					},
  2368  					{
  2369  						Key:      "test2",
  2370  						ZoneSize: "20M",
  2371  						Rate:     "20r/s",
  2372  						ZoneName: "pol_rl_default_rateLimit-policy2_default_test",
  2373  					},
  2374  				},
  2375  				LimitReqOptions: version2.LimitReqOptions{
  2376  					LogLevel:   "error",
  2377  					RejectCode: 503,
  2378  				},
  2379  				LimitReqs: []version2.LimitReq{
  2380  					{
  2381  						ZoneName: "pol_rl_default_rateLimit-policy_default_test",
  2382  					},
  2383  					{
  2384  						ZoneName: "pol_rl_default_rateLimit-policy2_default_test",
  2385  					},
  2386  				},
  2387  			},
  2388  			expectedWarnings: Warnings{
  2389  				nil: {
  2390  					`RateLimit policy default/rateLimit-policy2 with limit request option dryRun='true' is overridden to dryRun='false' by the first policy reference in this context`,
  2391  					`RateLimit policy default/rateLimit-policy2 with limit request option logLevel='info' is overridden to logLevel='error' by the first policy reference in this context`,
  2392  					`RateLimit policy default/rateLimit-policy2 with limit request option rejectCode='505' is overridden to rejectCode='503' by the first policy reference in this context`,
  2393  				},
  2394  			},
  2395  			expectedOidc: &oidcPolicyCfg{},
  2396  			msg:          "rate limit policy limit request option override",
  2397  		},
  2398  		{
  2399  			policyRefs: []conf_v1.PolicyReference{
  2400  				{
  2401  					Name:      "jwt-policy",
  2402  					Namespace: "default",
  2403  				},
  2404  			},
  2405  			policies: map[string]*conf_v1.Policy{
  2406  				"default/jwt-policy": {
  2407  					ObjectMeta: meta_v1.ObjectMeta{
  2408  						Name:      "jwt-policy",
  2409  						Namespace: "default",
  2410  					},
  2411  					Spec: conf_v1.PolicySpec{
  2412  						JWTAuth: &conf_v1.JWTAuth{
  2413  							Realm:  "test",
  2414  							Secret: "jwt-secret",
  2415  						},
  2416  					},
  2417  				},
  2418  			},
  2419  			policyOpts: policyOptions{
  2420  				secretRefs: map[string]*secrets.SecretReference{
  2421  					"default/jwt-secret": {
  2422  						Secret: &api_v1.Secret{
  2423  							Type: secrets.SecretTypeJWK,
  2424  						},
  2425  						Error: errors.New("secret is invalid"),
  2426  					},
  2427  				},
  2428  			},
  2429  			expected: policiesCfg{
  2430  				ErrorReturn: &version2.Return{
  2431  					Code: 500,
  2432  				},
  2433  			},
  2434  			expectedWarnings: Warnings{
  2435  				nil: {
  2436  					`JWT policy default/jwt-policy references an invalid secret default/jwt-secret: secret is invalid`,
  2437  				},
  2438  			},
  2439  			expectedOidc: &oidcPolicyCfg{},
  2440  			msg:          "jwt reference missing secret",
  2441  		},
  2442  		{
  2443  			policyRefs: []conf_v1.PolicyReference{
  2444  				{
  2445  					Name:      "jwt-policy",
  2446  					Namespace: "default",
  2447  				},
  2448  			},
  2449  			policies: map[string]*conf_v1.Policy{
  2450  				"default/jwt-policy": {
  2451  					ObjectMeta: meta_v1.ObjectMeta{
  2452  						Name:      "jwt-policy",
  2453  						Namespace: "default",
  2454  					},
  2455  					Spec: conf_v1.PolicySpec{
  2456  						JWTAuth: &conf_v1.JWTAuth{
  2457  							Realm:  "test",
  2458  							Secret: "jwt-secret",
  2459  						},
  2460  					},
  2461  				},
  2462  			},
  2463  			policyOpts: policyOptions{
  2464  				secretRefs: map[string]*secrets.SecretReference{
  2465  					"default/jwt-secret": {
  2466  						Secret: &api_v1.Secret{
  2467  							Type: secrets.SecretTypeCA,
  2468  						},
  2469  					},
  2470  				},
  2471  			},
  2472  			expected: policiesCfg{
  2473  				ErrorReturn: &version2.Return{
  2474  					Code: 500,
  2475  				},
  2476  			},
  2477  			expectedWarnings: Warnings{
  2478  				nil: {
  2479  					`JWT policy default/jwt-policy references a secret default/jwt-secret of a wrong type 'nginx.org/ca', must be 'nginx.org/jwk'`,
  2480  				},
  2481  			},
  2482  			expectedOidc: &oidcPolicyCfg{},
  2483  			msg:          "jwt references wrong secret type",
  2484  		},
  2485  		{
  2486  			policyRefs: []conf_v1.PolicyReference{
  2487  				{
  2488  					Name:      "jwt-policy",
  2489  					Namespace: "default",
  2490  				},
  2491  				{
  2492  					Name:      "jwt-policy2",
  2493  					Namespace: "default",
  2494  				},
  2495  			},
  2496  			policies: map[string]*conf_v1.Policy{
  2497  				"default/jwt-policy": {
  2498  					ObjectMeta: meta_v1.ObjectMeta{
  2499  						Name:      "jwt-policy",
  2500  						Namespace: "default",
  2501  					},
  2502  					Spec: conf_v1.PolicySpec{
  2503  						JWTAuth: &conf_v1.JWTAuth{
  2504  							Realm:  "test",
  2505  							Secret: "jwt-secret",
  2506  						},
  2507  					},
  2508  				},
  2509  				"default/jwt-policy2": {
  2510  					ObjectMeta: meta_v1.ObjectMeta{
  2511  						Name:      "jwt-policy2",
  2512  						Namespace: "default",
  2513  					},
  2514  					Spec: conf_v1.PolicySpec{
  2515  						JWTAuth: &conf_v1.JWTAuth{
  2516  							Realm:  "test",
  2517  							Secret: "jwt-secret2",
  2518  						},
  2519  					},
  2520  				},
  2521  			},
  2522  			policyOpts: policyOptions{
  2523  				secretRefs: map[string]*secrets.SecretReference{
  2524  					"default/jwt-secret": {
  2525  						Secret: &api_v1.Secret{
  2526  							Type: secrets.SecretTypeJWK,
  2527  						},
  2528  						Path: "/etc/nginx/secrets/default-jwt-secret",
  2529  					},
  2530  					"default/jwt-secret2": {
  2531  						Secret: &api_v1.Secret{
  2532  							Type: secrets.SecretTypeJWK,
  2533  						},
  2534  						Path: "/etc/nginx/secrets/default-jwt-secret2",
  2535  					},
  2536  				},
  2537  			},
  2538  			expected: policiesCfg{
  2539  				JWTAuth: &version2.JWTAuth{
  2540  					Secret: "/etc/nginx/secrets/default-jwt-secret",
  2541  					Realm:  "test",
  2542  				},
  2543  			},
  2544  			expectedWarnings: Warnings{
  2545  				nil: {
  2546  					`Multiple jwt policies in the same context is not valid. JWT policy default/jwt-policy2 will be ignored`,
  2547  				},
  2548  			},
  2549  			expectedOidc: &oidcPolicyCfg{},
  2550  			msg:          "multi jwt reference",
  2551  		},
  2552  		{
  2553  			policyRefs: []conf_v1.PolicyReference{
  2554  				{
  2555  					Name:      "ingress-mtls-policy",
  2556  					Namespace: "default",
  2557  				},
  2558  			},
  2559  			policies: map[string]*conf_v1.Policy{
  2560  				"default/ingress-mtls-policy": {
  2561  					ObjectMeta: meta_v1.ObjectMeta{
  2562  						Name:      "ingress-mtls-policy",
  2563  						Namespace: "default",
  2564  					},
  2565  					Spec: conf_v1.PolicySpec{
  2566  						IngressMTLS: &conf_v1.IngressMTLS{
  2567  							ClientCertSecret: "ingress-mtls-secret",
  2568  						},
  2569  					},
  2570  				},
  2571  			},
  2572  			policyOpts: policyOptions{
  2573  				tls: true,
  2574  				secretRefs: map[string]*secrets.SecretReference{
  2575  					"default/ingress-mtls-secret": {
  2576  						Error: errors.New("secret is invalid"),
  2577  					},
  2578  				},
  2579  			},
  2580  			context: "spec",
  2581  			expected: policiesCfg{
  2582  				ErrorReturn: &version2.Return{
  2583  					Code: 500,
  2584  				},
  2585  			},
  2586  			expectedWarnings: Warnings{
  2587  				nil: {
  2588  					`IngressMTLS policy "default/ingress-mtls-policy" references an invalid secret default/ingress-mtls-secret: secret is invalid`,
  2589  				},
  2590  			},
  2591  			expectedOidc: &oidcPolicyCfg{},
  2592  			msg:          "ingress mtls reference an invalid secret",
  2593  		},
  2594  		{
  2595  			policyRefs: []conf_v1.PolicyReference{
  2596  				{
  2597  					Name:      "ingress-mtls-policy",
  2598  					Namespace: "default",
  2599  				},
  2600  			},
  2601  			policies: map[string]*conf_v1.Policy{
  2602  				"default/ingress-mtls-policy": {
  2603  					ObjectMeta: meta_v1.ObjectMeta{
  2604  						Name:      "ingress-mtls-policy",
  2605  						Namespace: "default",
  2606  					},
  2607  					Spec: conf_v1.PolicySpec{
  2608  						IngressMTLS: &conf_v1.IngressMTLS{
  2609  							ClientCertSecret: "ingress-mtls-secret",
  2610  						},
  2611  					},
  2612  				},
  2613  			},
  2614  			policyOpts: policyOptions{
  2615  				tls: true,
  2616  				secretRefs: map[string]*secrets.SecretReference{
  2617  					"default/ingress-mtls-secret": {
  2618  						Secret: &api_v1.Secret{
  2619  							Type: api_v1.SecretTypeTLS,
  2620  						},
  2621  					},
  2622  				},
  2623  			},
  2624  			context: "spec",
  2625  			expected: policiesCfg{
  2626  				ErrorReturn: &version2.Return{
  2627  					Code: 500,
  2628  				},
  2629  			},
  2630  			expectedWarnings: Warnings{
  2631  				nil: {
  2632  					`IngressMTLS policy default/ingress-mtls-policy references a secret default/ingress-mtls-secret of a wrong type 'kubernetes.io/tls', must be 'nginx.org/ca'`,
  2633  				},
  2634  			},
  2635  			expectedOidc: &oidcPolicyCfg{},
  2636  			msg:          "ingress mtls references wrong secret type",
  2637  		},
  2638  		{
  2639  			policyRefs: []conf_v1.PolicyReference{
  2640  				{
  2641  					Name:      "ingress-mtls-policy",
  2642  					Namespace: "default",
  2643  				},
  2644  				{
  2645  					Name:      "ingress-mtls-policy2",
  2646  					Namespace: "default",
  2647  				},
  2648  			},
  2649  			policies: map[string]*conf_v1.Policy{
  2650  				"default/ingress-mtls-policy": {
  2651  					ObjectMeta: meta_v1.ObjectMeta{
  2652  						Name:      "ingress-mtls-policy",
  2653  						Namespace: "default",
  2654  					},
  2655  					Spec: conf_v1.PolicySpec{
  2656  						IngressMTLS: &conf_v1.IngressMTLS{
  2657  							ClientCertSecret: "ingress-mtls-secret",
  2658  						},
  2659  					},
  2660  				},
  2661  				"default/ingress-mtls-policy2": {
  2662  					Spec: conf_v1.PolicySpec{
  2663  						IngressMTLS: &conf_v1.IngressMTLS{
  2664  							ClientCertSecret: "ingress-mtls-secret2",
  2665  						},
  2666  					},
  2667  				},
  2668  			},
  2669  			policyOpts: policyOptions{
  2670  				tls: true,
  2671  				secretRefs: map[string]*secrets.SecretReference{
  2672  					"default/ingress-mtls-secret": {
  2673  						Secret: &api_v1.Secret{
  2674  							Type: secrets.SecretTypeCA,
  2675  						},
  2676  						Path: "/etc/nginx/secrets/default-ingress-mtls-secret",
  2677  					},
  2678  				},
  2679  			},
  2680  			context: "spec",
  2681  			expected: policiesCfg{
  2682  				IngressMTLS: &version2.IngressMTLS{
  2683  					ClientCert:   "/etc/nginx/secrets/default-ingress-mtls-secret",
  2684  					VerifyClient: "on",
  2685  					VerifyDepth:  1,
  2686  				},
  2687  			},
  2688  			expectedWarnings: Warnings{
  2689  				nil: {
  2690  					`Multiple ingressMTLS policies are not allowed. IngressMTLS policy default/ingress-mtls-policy2 will be ignored`,
  2691  				},
  2692  			},
  2693  			expectedOidc: &oidcPolicyCfg{},
  2694  			msg:          "multi ingress mtls",
  2695  		},
  2696  		{
  2697  			policyRefs: []conf_v1.PolicyReference{
  2698  				{
  2699  					Name:      "ingress-mtls-policy",
  2700  					Namespace: "default",
  2701  				},
  2702  			},
  2703  			policies: map[string]*conf_v1.Policy{
  2704  				"default/ingress-mtls-policy": {
  2705  					ObjectMeta: meta_v1.ObjectMeta{
  2706  						Name:      "ingress-mtls-policy",
  2707  						Namespace: "default",
  2708  					},
  2709  					Spec: conf_v1.PolicySpec{
  2710  						IngressMTLS: &conf_v1.IngressMTLS{
  2711  							ClientCertSecret: "ingress-mtls-secret",
  2712  						},
  2713  					},
  2714  				},
  2715  			},
  2716  			policyOpts: policyOptions{
  2717  				tls: true,
  2718  				secretRefs: map[string]*secrets.SecretReference{
  2719  					"default/ingress-mtls-secret": {
  2720  						Secret: &api_v1.Secret{
  2721  							Type: secrets.SecretTypeCA,
  2722  						},
  2723  						Path: "/etc/nginx/secrets/default-ingress-mtls-secret",
  2724  					},
  2725  				},
  2726  			},
  2727  			context: "route",
  2728  			expected: policiesCfg{
  2729  				ErrorReturn: &version2.Return{
  2730  					Code: 500,
  2731  				},
  2732  			},
  2733  			expectedWarnings: Warnings{
  2734  				nil: {
  2735  					`IngressMTLS policy default/ingress-mtls-policy is not allowed in the route context`,
  2736  				},
  2737  			},
  2738  			expectedOidc: &oidcPolicyCfg{},
  2739  			msg:          "ingress mtls in the wrong context",
  2740  		},
  2741  		{
  2742  			policyRefs: []conf_v1.PolicyReference{
  2743  				{
  2744  					Name:      "ingress-mtls-policy",
  2745  					Namespace: "default",
  2746  				},
  2747  			},
  2748  			policies: map[string]*conf_v1.Policy{
  2749  				"default/ingress-mtls-policy": {
  2750  					ObjectMeta: meta_v1.ObjectMeta{
  2751  						Name:      "ingress-mtls-policy",
  2752  						Namespace: "default",
  2753  					},
  2754  					Spec: conf_v1.PolicySpec{
  2755  						IngressMTLS: &conf_v1.IngressMTLS{
  2756  							ClientCertSecret: "ingress-mtls-secret",
  2757  						},
  2758  					},
  2759  				},
  2760  			},
  2761  			policyOpts: policyOptions{
  2762  				tls: false,
  2763  				secretRefs: map[string]*secrets.SecretReference{
  2764  					"default/ingress-mtls-secret": {
  2765  						Secret: &api_v1.Secret{
  2766  							Type: secrets.SecretTypeCA,
  2767  						},
  2768  						Path: "/etc/nginx/secrets/default-ingress-mtls-secret",
  2769  					},
  2770  				},
  2771  			},
  2772  			context: "route",
  2773  			expected: policiesCfg{
  2774  				ErrorReturn: &version2.Return{
  2775  					Code: 500,
  2776  				},
  2777  			},
  2778  			expectedWarnings: Warnings{
  2779  				nil: {
  2780  					`TLS must be enabled in VirtualServer for IngressMTLS policy default/ingress-mtls-policy`,
  2781  				},
  2782  			},
  2783  			expectedOidc: &oidcPolicyCfg{},
  2784  			msg:          "ingress mtls missing TLS config",
  2785  		},
  2786  		{
  2787  			policyRefs: []conf_v1.PolicyReference{
  2788  				{
  2789  					Name:      "egress-mtls-policy",
  2790  					Namespace: "default",
  2791  				},
  2792  				{
  2793  					Name:      "egress-mtls-policy2",
  2794  					Namespace: "default",
  2795  				},
  2796  			},
  2797  			policies: map[string]*conf_v1.Policy{
  2798  				"default/egress-mtls-policy": {
  2799  					ObjectMeta: meta_v1.ObjectMeta{
  2800  						Name:      "egress-mtls-policy",
  2801  						Namespace: "default",
  2802  					},
  2803  					Spec: conf_v1.PolicySpec{
  2804  						EgressMTLS: &conf_v1.EgressMTLS{
  2805  							TLSSecret: "egress-mtls-secret",
  2806  						},
  2807  					},
  2808  				},
  2809  				"default/egress-mtls-policy2": {
  2810  					ObjectMeta: meta_v1.ObjectMeta{
  2811  						Name:      "egress-mtls-policy2",
  2812  						Namespace: "default",
  2813  					},
  2814  					Spec: conf_v1.PolicySpec{
  2815  						EgressMTLS: &conf_v1.EgressMTLS{
  2816  							TLSSecret: "egress-mtls-secret2",
  2817  						},
  2818  					},
  2819  				},
  2820  			},
  2821  			policyOpts: policyOptions{
  2822  				secretRefs: map[string]*secrets.SecretReference{
  2823  					"default/egress-mtls-secret": {
  2824  						Secret: &api_v1.Secret{
  2825  							Type: api_v1.SecretTypeTLS,
  2826  						},
  2827  						Path: "/etc/nginx/secrets/default-egress-mtls-secret",
  2828  					},
  2829  				},
  2830  			},
  2831  			context: "route",
  2832  			expected: policiesCfg{
  2833  				EgressMTLS: &version2.EgressMTLS{
  2834  					Certificate:    "/etc/nginx/secrets/default-egress-mtls-secret",
  2835  					CertificateKey: "/etc/nginx/secrets/default-egress-mtls-secret",
  2836  					VerifyServer:   false,
  2837  					VerifyDepth:    1,
  2838  					Ciphers:        "DEFAULT",
  2839  					Protocols:      "TLSv1 TLSv1.1 TLSv1.2",
  2840  					SessionReuse:   true,
  2841  					SSLName:        "$proxy_host",
  2842  				},
  2843  			},
  2844  			expectedWarnings: Warnings{
  2845  				nil: {
  2846  					`Multiple egressMTLS policies in the same context is not valid. EgressMTLS policy default/egress-mtls-policy2 will be ignored`,
  2847  				},
  2848  			},
  2849  			expectedOidc: &oidcPolicyCfg{},
  2850  			msg:          "multi egress mtls",
  2851  		},
  2852  		{
  2853  			policyRefs: []conf_v1.PolicyReference{
  2854  				{
  2855  					Name:      "egress-mtls-policy",
  2856  					Namespace: "default",
  2857  				},
  2858  			},
  2859  			policies: map[string]*conf_v1.Policy{
  2860  				"default/egress-mtls-policy": {
  2861  					ObjectMeta: meta_v1.ObjectMeta{
  2862  						Name:      "egress-mtls-policy",
  2863  						Namespace: "default",
  2864  					},
  2865  					Spec: conf_v1.PolicySpec{
  2866  						EgressMTLS: &conf_v1.EgressMTLS{
  2867  							TrustedCertSecret: "egress-trusted-secret",
  2868  							SSLName:           "foo.com",
  2869  						},
  2870  					},
  2871  				},
  2872  			},
  2873  			policyOpts: policyOptions{
  2874  				secretRefs: map[string]*secrets.SecretReference{
  2875  					"default/egress-trusted-secret": {
  2876  						Secret: &api_v1.Secret{
  2877  							Type: secrets.SecretTypeCA,
  2878  						},
  2879  						Error: errors.New("secret is invalid"),
  2880  					},
  2881  				},
  2882  			},
  2883  			context: "route",
  2884  			expected: policiesCfg{
  2885  				ErrorReturn: &version2.Return{
  2886  					Code: 500,
  2887  				},
  2888  			},
  2889  			expectedWarnings: Warnings{
  2890  				nil: {
  2891  					`EgressMTLS policy default/egress-mtls-policy references an invalid secret default/egress-trusted-secret: secret is invalid`,
  2892  				},
  2893  			},
  2894  			expectedOidc: &oidcPolicyCfg{},
  2895  			msg:          "egress mtls referencing an invalid CA secret",
  2896  		},
  2897  		{
  2898  			policyRefs: []conf_v1.PolicyReference{
  2899  				{
  2900  					Name:      "egress-mtls-policy",
  2901  					Namespace: "default",
  2902  				},
  2903  			},
  2904  			policies: map[string]*conf_v1.Policy{
  2905  				"default/egress-mtls-policy": {
  2906  					ObjectMeta: meta_v1.ObjectMeta{
  2907  						Name:      "egress-mtls-policy",
  2908  						Namespace: "default",
  2909  					},
  2910  					Spec: conf_v1.PolicySpec{
  2911  						EgressMTLS: &conf_v1.EgressMTLS{
  2912  							TLSSecret: "egress-mtls-secret",
  2913  							SSLName:   "foo.com",
  2914  						},
  2915  					},
  2916  				},
  2917  			},
  2918  			policyOpts: policyOptions{
  2919  				secretRefs: map[string]*secrets.SecretReference{
  2920  					"default/egress-mtls-secret": {
  2921  						Secret: &api_v1.Secret{
  2922  							Type: secrets.SecretTypeCA,
  2923  						},
  2924  					},
  2925  				},
  2926  			},
  2927  			context: "route",
  2928  			expected: policiesCfg{
  2929  				ErrorReturn: &version2.Return{
  2930  					Code: 500,
  2931  				},
  2932  			},
  2933  			expectedWarnings: Warnings{
  2934  				nil: {
  2935  					`EgressMTLS policy default/egress-mtls-policy references a secret default/egress-mtls-secret of a wrong type 'nginx.org/ca', must be 'kubernetes.io/tls'`,
  2936  				},
  2937  			},
  2938  			expectedOidc: &oidcPolicyCfg{},
  2939  			msg:          "egress mtls referencing wrong secret type",
  2940  		},
  2941  		{
  2942  			policyRefs: []conf_v1.PolicyReference{
  2943  				{
  2944  					Name:      "egress-mtls-policy",
  2945  					Namespace: "default",
  2946  				},
  2947  			},
  2948  			policies: map[string]*conf_v1.Policy{
  2949  				"default/egress-mtls-policy": {
  2950  					ObjectMeta: meta_v1.ObjectMeta{
  2951  						Name:      "egress-mtls-policy",
  2952  						Namespace: "default",
  2953  					},
  2954  					Spec: conf_v1.PolicySpec{
  2955  						EgressMTLS: &conf_v1.EgressMTLS{
  2956  							TrustedCertSecret: "egress-trusted-secret",
  2957  							SSLName:           "foo.com",
  2958  						},
  2959  					},
  2960  				},
  2961  			},
  2962  			policyOpts: policyOptions{
  2963  				secretRefs: map[string]*secrets.SecretReference{
  2964  					"default/egress-trusted-secret": {
  2965  						Secret: &api_v1.Secret{
  2966  							Type: api_v1.SecretTypeTLS,
  2967  						},
  2968  					},
  2969  				},
  2970  			},
  2971  			context: "route",
  2972  			expected: policiesCfg{
  2973  				ErrorReturn: &version2.Return{
  2974  					Code: 500,
  2975  				},
  2976  			},
  2977  			expectedWarnings: Warnings{
  2978  				nil: {
  2979  					`EgressMTLS policy default/egress-mtls-policy references a secret default/egress-trusted-secret of a wrong type 'kubernetes.io/tls', must be 'nginx.org/ca'`,
  2980  				},
  2981  			},
  2982  			expectedOidc: &oidcPolicyCfg{},
  2983  			msg:          "egress trusted secret referencing wrong secret type",
  2984  		},
  2985  		{
  2986  			policyRefs: []conf_v1.PolicyReference{
  2987  				{
  2988  					Name:      "egress-mtls-policy",
  2989  					Namespace: "default",
  2990  				},
  2991  			},
  2992  			policies: map[string]*conf_v1.Policy{
  2993  				"default/egress-mtls-policy": {
  2994  					ObjectMeta: meta_v1.ObjectMeta{
  2995  						Name:      "egress-mtls-policy",
  2996  						Namespace: "default",
  2997  					},
  2998  					Spec: conf_v1.PolicySpec{
  2999  						EgressMTLS: &conf_v1.EgressMTLS{
  3000  							TLSSecret: "egress-mtls-secret",
  3001  							SSLName:   "foo.com",
  3002  						},
  3003  					},
  3004  				},
  3005  			},
  3006  			policyOpts: policyOptions{
  3007  				secretRefs: map[string]*secrets.SecretReference{
  3008  					"default/egress-mtls-secret": {
  3009  						Secret: &api_v1.Secret{
  3010  							Type: api_v1.SecretTypeTLS,
  3011  						},
  3012  						Error: errors.New("secret is invalid"),
  3013  					},
  3014  				},
  3015  			},
  3016  			context: "route",
  3017  			expected: policiesCfg{
  3018  				ErrorReturn: &version2.Return{
  3019  					Code: 500,
  3020  				},
  3021  			},
  3022  			expectedWarnings: Warnings{
  3023  				nil: {
  3024  					`EgressMTLS policy default/egress-mtls-policy references an invalid secret default/egress-mtls-secret: secret is invalid`,
  3025  				},
  3026  			},
  3027  			expectedOidc: &oidcPolicyCfg{},
  3028  			msg:          "egress mtls referencing missing tls secret",
  3029  		},
  3030  		{
  3031  			policyRefs: []conf_v1.PolicyReference{
  3032  				{
  3033  					Name:      "oidc-policy",
  3034  					Namespace: "default",
  3035  				},
  3036  			},
  3037  			policies: map[string]*conf_v1.Policy{
  3038  				"default/oidc-policy": {
  3039  					ObjectMeta: meta_v1.ObjectMeta{
  3040  						Name:      "oidc-policy",
  3041  						Namespace: "default",
  3042  					},
  3043  					Spec: conf_v1.PolicySpec{
  3044  						OIDC: &conf_v1.OIDC{
  3045  							ClientSecret: "oidc-secret",
  3046  						},
  3047  					},
  3048  				},
  3049  			},
  3050  			policyOpts: policyOptions{
  3051  				secretRefs: map[string]*secrets.SecretReference{
  3052  					"default/oidc-secret": {
  3053  						Secret: &api_v1.Secret{
  3054  							Type: secrets.SecretTypeOIDC,
  3055  						},
  3056  						Error: errors.New("secret is invalid"),
  3057  					},
  3058  				},
  3059  			},
  3060  			context: "route",
  3061  			expected: policiesCfg{
  3062  				ErrorReturn: &version2.Return{
  3063  					Code: 500,
  3064  				},
  3065  			},
  3066  			expectedWarnings: Warnings{
  3067  				nil: {
  3068  					`OIDC policy default/oidc-policy references an invalid secret default/oidc-secret: secret is invalid`,
  3069  				},
  3070  			},
  3071  			expectedOidc: &oidcPolicyCfg{},
  3072  			msg:          "oidc referencing missing oidc secret",
  3073  		},
  3074  		{
  3075  			policyRefs: []conf_v1.PolicyReference{
  3076  				{
  3077  					Name:      "oidc-policy",
  3078  					Namespace: "default",
  3079  				},
  3080  			},
  3081  			policies: map[string]*conf_v1.Policy{
  3082  				"default/oidc-policy": {
  3083  					ObjectMeta: meta_v1.ObjectMeta{
  3084  						Name:      "oidc-policy",
  3085  						Namespace: "default",
  3086  					},
  3087  					Spec: conf_v1.PolicySpec{
  3088  						OIDC: &conf_v1.OIDC{
  3089  							ClientSecret:  "oidc-secret",
  3090  							AuthEndpoint:  "http://foo.com/bar",
  3091  							TokenEndpoint: "http://foo.com/bar",
  3092  							JWKSURI:       "http://foo.com/bar",
  3093  						},
  3094  					},
  3095  				},
  3096  			},
  3097  			policyOpts: policyOptions{
  3098  				secretRefs: map[string]*secrets.SecretReference{
  3099  					"default/oidc-secret": {
  3100  						Secret: &api_v1.Secret{
  3101  							Type: api_v1.SecretTypeTLS,
  3102  						},
  3103  					},
  3104  				},
  3105  			},
  3106  			context: "spec",
  3107  			expected: policiesCfg{
  3108  				ErrorReturn: &version2.Return{
  3109  					Code: 500,
  3110  				},
  3111  			},
  3112  			expectedWarnings: Warnings{
  3113  				nil: {
  3114  					`OIDC policy default/oidc-policy references a secret default/oidc-secret of a wrong type 'kubernetes.io/tls', must be 'nginx.org/oidc'`,
  3115  				},
  3116  			},
  3117  			expectedOidc: &oidcPolicyCfg{},
  3118  			msg:          "oidc secret referencing wrong secret type",
  3119  		},
  3120  		{
  3121  			policyRefs: []conf_v1.PolicyReference{
  3122  				{
  3123  					Name:      "oidc-policy-2",
  3124  					Namespace: "default",
  3125  				},
  3126  			},
  3127  			policies: map[string]*conf_v1.Policy{
  3128  				"default/oidc-policy-1": {
  3129  					ObjectMeta: meta_v1.ObjectMeta{
  3130  						Name:      "oidc-policy-1",
  3131  						Namespace: "default",
  3132  					},
  3133  					Spec: conf_v1.PolicySpec{
  3134  						OIDC: &conf_v1.OIDC{
  3135  							ClientID:      "foo",
  3136  							ClientSecret:  "oidc-secret",
  3137  							AuthEndpoint:  "https://foo.com/auth",
  3138  							TokenEndpoint: "https://foo.com/token",
  3139  							JWKSURI:       "https://foo.com/certs",
  3140  						},
  3141  					},
  3142  				},
  3143  				"default/oidc-policy-2": {
  3144  					ObjectMeta: meta_v1.ObjectMeta{
  3145  						Name:      "oidc-policy-2",
  3146  						Namespace: "default",
  3147  					},
  3148  					Spec: conf_v1.PolicySpec{
  3149  						OIDC: &conf_v1.OIDC{
  3150  							ClientID:      "foo",
  3151  							ClientSecret:  "oidc-secret",
  3152  							AuthEndpoint:  "https://bar.com/auth",
  3153  							TokenEndpoint: "https://bar.com/token",
  3154  							JWKSURI:       "https://bar.com/certs",
  3155  						},
  3156  					},
  3157  				},
  3158  			},
  3159  			policyOpts: policyOptions{
  3160  				secretRefs: map[string]*secrets.SecretReference{
  3161  					"default/oidc-secret": {
  3162  						Secret: &api_v1.Secret{
  3163  							Type: secrets.SecretTypeOIDC,
  3164  							Data: map[string][]byte{
  3165  								"client-secret": []byte("super_secret_123"),
  3166  							},
  3167  						},
  3168  					},
  3169  				},
  3170  			},
  3171  			context: "route",
  3172  			oidcPolCfg: &oidcPolicyCfg{
  3173  				oidc: &version2.OIDC{
  3174  					AuthEndpoint:  "https://foo.com/auth",
  3175  					TokenEndpoint: "https://foo.com/token",
  3176  					JwksURI:       "https://foo.com/certs",
  3177  					ClientID:      "foo",
  3178  					ClientSecret:  "super_secret_123",
  3179  					RedirectURI:   "/_codexch",
  3180  					Scope:         "openid",
  3181  				},
  3182  				key: "default/oidc-policy-1",
  3183  			},
  3184  			expected: policiesCfg{
  3185  				ErrorReturn: &version2.Return{
  3186  					Code: 500,
  3187  				},
  3188  			},
  3189  			expectedWarnings: Warnings{
  3190  				nil: {
  3191  					`Only one oidc policy is allowed in a VirtualServer and its VirtualServerRoutes. Can't use default/oidc-policy-2. Use default/oidc-policy-1`,
  3192  				},
  3193  			},
  3194  			expectedOidc: &oidcPolicyCfg{
  3195  				oidc: &version2.OIDC{
  3196  					AuthEndpoint:  "https://foo.com/auth",
  3197  					TokenEndpoint: "https://foo.com/token",
  3198  					JwksURI:       "https://foo.com/certs",
  3199  					ClientID:      "foo",
  3200  					ClientSecret:  "super_secret_123",
  3201  					RedirectURI:   "/_codexch",
  3202  					Scope:         "openid",
  3203  				},
  3204  				key: "default/oidc-policy-1",
  3205  			},
  3206  			msg: "multiple oidc policies",
  3207  		},
  3208  		{
  3209  			policyRefs: []conf_v1.PolicyReference{
  3210  				{
  3211  					Name:      "oidc-policy",
  3212  					Namespace: "default",
  3213  				},
  3214  				{
  3215  					Name:      "oidc-policy2",
  3216  					Namespace: "default",
  3217  				},
  3218  			},
  3219  			policies: map[string]*conf_v1.Policy{
  3220  				"default/oidc-policy": {
  3221  					ObjectMeta: meta_v1.ObjectMeta{
  3222  						Name:      "oidc-policy",
  3223  						Namespace: "default",
  3224  					},
  3225  					Spec: conf_v1.PolicySpec{
  3226  						OIDC: &conf_v1.OIDC{
  3227  							ClientSecret:  "oidc-secret",
  3228  							AuthEndpoint:  "https://foo.com/auth",
  3229  							TokenEndpoint: "https://foo.com/token",
  3230  							JWKSURI:       "https://foo.com/certs",
  3231  							ClientID:      "foo",
  3232  						},
  3233  					},
  3234  				},
  3235  				"default/oidc-policy2": {
  3236  					ObjectMeta: meta_v1.ObjectMeta{
  3237  						Name:      "oidc-policy2",
  3238  						Namespace: "default",
  3239  					},
  3240  					Spec: conf_v1.PolicySpec{
  3241  						OIDC: &conf_v1.OIDC{
  3242  							ClientSecret:  "oidc-secret",
  3243  							AuthEndpoint:  "https://bar.com/auth",
  3244  							TokenEndpoint: "https://bar.com/token",
  3245  							JWKSURI:       "https://bar.com/certs",
  3246  							ClientID:      "bar",
  3247  						},
  3248  					},
  3249  				},
  3250  			},
  3251  			policyOpts: policyOptions{
  3252  				secretRefs: map[string]*secrets.SecretReference{
  3253  					"default/oidc-secret": {
  3254  						Secret: &api_v1.Secret{
  3255  							Type: secrets.SecretTypeOIDC,
  3256  							Data: map[string][]byte{
  3257  								"client-secret": []byte("super_secret_123"),
  3258  							},
  3259  						},
  3260  					},
  3261  				},
  3262  			},
  3263  			context: "route",
  3264  			expected: policiesCfg{
  3265  				OIDC: true,
  3266  			},
  3267  			expectedWarnings: Warnings{
  3268  				nil: {
  3269  					`Multiple oidc policies in the same context is not valid. OIDC policy default/oidc-policy2 will be ignored`,
  3270  				},
  3271  			},
  3272  			expectedOidc: &oidcPolicyCfg{
  3273  				&version2.OIDC{
  3274  					AuthEndpoint:  "https://foo.com/auth",
  3275  					TokenEndpoint: "https://foo.com/token",
  3276  					JwksURI:       "https://foo.com/certs",
  3277  					ClientID:      "foo",
  3278  					ClientSecret:  "super_secret_123",
  3279  					RedirectURI:   "/_codexch",
  3280  					Scope:         "openid",
  3281  				},
  3282  				"default/oidc-policy",
  3283  			},
  3284  			msg: "multi oidc",
  3285  		},
  3286  		{
  3287  			policyRefs: []conf_v1.PolicyReference{
  3288  				{
  3289  					Name:      "waf-policy",
  3290  					Namespace: "default",
  3291  				},
  3292  				{
  3293  					Name:      "waf-policy2",
  3294  					Namespace: "default",
  3295  				},
  3296  			},
  3297  			policies: map[string]*conf_v1.Policy{
  3298  				"default/waf-policy": {
  3299  					ObjectMeta: meta_v1.ObjectMeta{
  3300  						Name:      "waf-policy",
  3301  						Namespace: "default",
  3302  					},
  3303  					Spec: conf_v1.PolicySpec{
  3304  						WAF: &conf_v1.WAF{
  3305  							Enable:   true,
  3306  							ApPolicy: "default/dataguard-alarm",
  3307  						},
  3308  					},
  3309  				},
  3310  				"default/waf-policy2": {
  3311  					ObjectMeta: meta_v1.ObjectMeta{
  3312  						Name:      "waf-policy2",
  3313  						Namespace: "default",
  3314  					},
  3315  					Spec: conf_v1.PolicySpec{
  3316  						WAF: &conf_v1.WAF{
  3317  							Enable:   true,
  3318  							ApPolicy: "default/dataguard-alarm",
  3319  						},
  3320  					},
  3321  				},
  3322  			},
  3323  			policyOpts: policyOptions{
  3324  				apResources: map[string]string{
  3325  					"default/logconf":         "/etc/nginx/waf/nac-logconfs/default-logconf",
  3326  					"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  3327  				},
  3328  			},
  3329  			context: "route",
  3330  			expected: policiesCfg{
  3331  				WAF: &version2.WAF{
  3332  					Enable:   "on",
  3333  					ApPolicy: "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  3334  				},
  3335  			},
  3336  			expectedWarnings: Warnings{
  3337  				nil: {
  3338  					`Multiple WAF policies in the same context is not valid. WAF policy default/waf-policy2 will be ignored`,
  3339  				},
  3340  			},
  3341  			expectedOidc: &oidcPolicyCfg{},
  3342  			msg:          "multi waf",
  3343  		},
  3344  	}
  3345  
  3346  	for _, test := range tests {
  3347  		vsc := newVirtualServerConfigurator(&ConfigParams{}, false, false, &StaticConfigParams{})
  3348  
  3349  		if test.oidcPolCfg != nil {
  3350  			vsc.oidcPolCfg = test.oidcPolCfg
  3351  		}
  3352  
  3353  		result := vsc.generatePolicies(ownerDetails, test.policyRefs, test.policies, test.context, test.policyOpts)
  3354  		if diff := cmp.Diff(test.expected, result); diff != "" {
  3355  			t.Errorf("generatePolicies() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  3356  		}
  3357  		if !reflect.DeepEqual(vsc.warnings, test.expectedWarnings) {
  3358  			t.Errorf(
  3359  				"generatePolicies() returned warnings of \n%v but expected \n%v for the case of %s",
  3360  				vsc.warnings,
  3361  				test.expectedWarnings,
  3362  				test.msg,
  3363  			)
  3364  		}
  3365  		if diff := cmp.Diff(test.expectedOidc.oidc, vsc.oidcPolCfg.oidc); diff != "" {
  3366  			t.Errorf("generatePolicies() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  3367  		}
  3368  		if diff := cmp.Diff(test.expectedOidc.key, vsc.oidcPolCfg.key); diff != "" {
  3369  			t.Errorf("generatePolicies() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  3370  		}
  3371  	}
  3372  }
  3373  
  3374  func TestRemoveDuplicates(t *testing.T) {
  3375  	tests := []struct {
  3376  		rlz      []version2.LimitReqZone
  3377  		expected []version2.LimitReqZone
  3378  	}{
  3379  		{
  3380  			rlz: []version2.LimitReqZone{
  3381  				{ZoneName: "test"},
  3382  				{ZoneName: "test"},
  3383  				{ZoneName: "test2"},
  3384  				{ZoneName: "test3"},
  3385  			},
  3386  			expected: []version2.LimitReqZone{
  3387  				{ZoneName: "test"},
  3388  				{ZoneName: "test2"},
  3389  				{ZoneName: "test3"},
  3390  			},
  3391  		},
  3392  		{
  3393  			rlz: []version2.LimitReqZone{
  3394  				{ZoneName: "test"},
  3395  				{ZoneName: "test"},
  3396  				{ZoneName: "test2"},
  3397  				{ZoneName: "test3"},
  3398  				{ZoneName: "test3"},
  3399  			},
  3400  			expected: []version2.LimitReqZone{
  3401  				{ZoneName: "test"},
  3402  				{ZoneName: "test2"},
  3403  				{ZoneName: "test3"},
  3404  			},
  3405  		},
  3406  	}
  3407  	for _, test := range tests {
  3408  		result := removeDuplicateLimitReqZones(test.rlz)
  3409  		if !reflect.DeepEqual(result, test.expected) {
  3410  			t.Errorf("removeDuplicateLimitReqZones() returned \n%v, but expected \n%v", result, test.expected)
  3411  		}
  3412  	}
  3413  }
  3414  
  3415  func TestAddPoliciesCfgToLocations(t *testing.T) {
  3416  	cfg := policiesCfg{
  3417  		Allow: []string{"127.0.0.1"},
  3418  		Deny:  []string{"127.0.0.2"},
  3419  		ErrorReturn: &version2.Return{
  3420  			Code: 400,
  3421  		},
  3422  	}
  3423  
  3424  	locations := []version2.Location{
  3425  		{
  3426  			Path: "/",
  3427  		},
  3428  	}
  3429  
  3430  	expectedLocations := []version2.Location{
  3431  		{
  3432  			Path:  "/",
  3433  			Allow: []string{"127.0.0.1"},
  3434  			Deny:  []string{"127.0.0.2"},
  3435  			PoliciesErrorReturn: &version2.Return{
  3436  				Code: 400,
  3437  			},
  3438  		},
  3439  	}
  3440  
  3441  	addPoliciesCfgToLocations(cfg, locations)
  3442  	if !reflect.DeepEqual(locations, expectedLocations) {
  3443  		t.Errorf("addPoliciesCfgToLocations() returned \n%+v but expected \n%+v", locations, expectedLocations)
  3444  	}
  3445  }
  3446  
  3447  func TestGenerateUpstream(t *testing.T) {
  3448  	name := "test-upstream"
  3449  	upstream := conf_v1.Upstream{Service: name, Port: 80}
  3450  	endpoints := []string{
  3451  		"192.168.10.10:8080",
  3452  	}
  3453  	cfgParams := ConfigParams{
  3454  		LBMethod:         "random",
  3455  		MaxFails:         1,
  3456  		MaxConns:         0,
  3457  		FailTimeout:      "10s",
  3458  		Keepalive:        21,
  3459  		UpstreamZoneSize: "256k",
  3460  	}
  3461  
  3462  	expected := version2.Upstream{
  3463  		Name: "test-upstream",
  3464  		UpstreamLabels: version2.UpstreamLabels{
  3465  			Service: "test-upstream",
  3466  		},
  3467  		Servers: []version2.UpstreamServer{
  3468  			{
  3469  				Address: "192.168.10.10:8080",
  3470  			},
  3471  		},
  3472  		MaxFails:         1,
  3473  		MaxConns:         0,
  3474  		FailTimeout:      "10s",
  3475  		LBMethod:         "random",
  3476  		Keepalive:        21,
  3477  		UpstreamZoneSize: "256k",
  3478  	}
  3479  
  3480  	vsc := newVirtualServerConfigurator(&cfgParams, false, false, &StaticConfigParams{})
  3481  	result := vsc.generateUpstream(nil, name, upstream, false, endpoints)
  3482  	if !reflect.DeepEqual(result, expected) {
  3483  		t.Errorf("generateUpstream() returned %v but expected %v", result, expected)
  3484  	}
  3485  
  3486  	if len(vsc.warnings) != 0 {
  3487  		t.Errorf("generateUpstream returned warnings for %v", upstream)
  3488  	}
  3489  }
  3490  
  3491  func TestGenerateUpstreamWithKeepalive(t *testing.T) {
  3492  	name := "test-upstream"
  3493  	noKeepalive := 0
  3494  	keepalive := 32
  3495  	endpoints := []string{
  3496  		"192.168.10.10:8080",
  3497  	}
  3498  
  3499  	tests := []struct {
  3500  		upstream  conf_v1.Upstream
  3501  		cfgParams *ConfigParams
  3502  		expected  version2.Upstream
  3503  		msg       string
  3504  	}{
  3505  		{
  3506  			conf_v1.Upstream{Keepalive: &keepalive, Service: name, Port: 80},
  3507  			&ConfigParams{Keepalive: 21},
  3508  			version2.Upstream{
  3509  				Name: "test-upstream",
  3510  				UpstreamLabels: version2.UpstreamLabels{
  3511  					Service: "test-upstream",
  3512  				},
  3513  				Servers: []version2.UpstreamServer{
  3514  					{
  3515  						Address: "192.168.10.10:8080",
  3516  					},
  3517  				},
  3518  				Keepalive: 32,
  3519  			},
  3520  			"upstream keepalive set, configparam set",
  3521  		},
  3522  		{
  3523  			conf_v1.Upstream{Service: name, Port: 80},
  3524  			&ConfigParams{Keepalive: 21},
  3525  			version2.Upstream{
  3526  				Name: "test-upstream",
  3527  				UpstreamLabels: version2.UpstreamLabels{
  3528  					Service: "test-upstream",
  3529  				},
  3530  				Servers: []version2.UpstreamServer{
  3531  					{
  3532  						Address: "192.168.10.10:8080",
  3533  					},
  3534  				},
  3535  				Keepalive: 21,
  3536  			},
  3537  			"upstream keepalive not set, configparam set",
  3538  		},
  3539  		{
  3540  			conf_v1.Upstream{Keepalive: &noKeepalive, Service: name, Port: 80},
  3541  			&ConfigParams{Keepalive: 21},
  3542  			version2.Upstream{
  3543  				Name: "test-upstream",
  3544  				UpstreamLabels: version2.UpstreamLabels{
  3545  					Service: "test-upstream",
  3546  				},
  3547  				Servers: []version2.UpstreamServer{
  3548  					{
  3549  						Address: "192.168.10.10:8080",
  3550  					},
  3551  				},
  3552  			},
  3553  			"upstream keepalive set to 0, configparam set",
  3554  		},
  3555  	}
  3556  
  3557  	for _, test := range tests {
  3558  		vsc := newVirtualServerConfigurator(test.cfgParams, false, false, &StaticConfigParams{})
  3559  		result := vsc.generateUpstream(nil, name, test.upstream, false, endpoints)
  3560  		if !reflect.DeepEqual(result, test.expected) {
  3561  			t.Errorf("generateUpstream() returned %v but expected %v for the case of %v", result, test.expected, test.msg)
  3562  		}
  3563  
  3564  		if len(vsc.warnings) != 0 {
  3565  			t.Errorf("generateUpstream() returned warnings for %v", test.upstream)
  3566  		}
  3567  	}
  3568  }
  3569  
  3570  func TestGenerateUpstreamForExternalNameService(t *testing.T) {
  3571  	name := "test-upstream"
  3572  	endpoints := []string{"example.com"}
  3573  	upstream := conf_v1.Upstream{Service: name}
  3574  	cfgParams := ConfigParams{}
  3575  
  3576  	expected := version2.Upstream{
  3577  		Name: name,
  3578  		UpstreamLabels: version2.UpstreamLabels{
  3579  			Service: "test-upstream",
  3580  		},
  3581  		Servers: []version2.UpstreamServer{
  3582  			{
  3583  				Address: "example.com",
  3584  			},
  3585  		},
  3586  		Resolve: true,
  3587  	}
  3588  
  3589  	vsc := newVirtualServerConfigurator(&cfgParams, true, true, &StaticConfigParams{})
  3590  	result := vsc.generateUpstream(nil, name, upstream, true, endpoints)
  3591  	if !reflect.DeepEqual(result, expected) {
  3592  		t.Errorf("generateUpstream() returned %v but expected %v", result, expected)
  3593  	}
  3594  
  3595  	if len(vsc.warnings) != 0 {
  3596  		t.Errorf("generateUpstream() returned warnings for %v", upstream)
  3597  	}
  3598  }
  3599  
  3600  func TestGenerateProxyPass(t *testing.T) {
  3601  	tests := []struct {
  3602  		tlsEnabled   bool
  3603  		upstreamName string
  3604  		internal     bool
  3605  		expected     string
  3606  	}{
  3607  		{
  3608  			tlsEnabled:   false,
  3609  			upstreamName: "test-upstream",
  3610  			internal:     false,
  3611  			expected:     "http://test-upstream",
  3612  		},
  3613  		{
  3614  			tlsEnabled:   true,
  3615  			upstreamName: "test-upstream",
  3616  			internal:     false,
  3617  			expected:     "https://test-upstream",
  3618  		},
  3619  		{
  3620  			tlsEnabled:   false,
  3621  			upstreamName: "test-upstream",
  3622  			internal:     true,
  3623  			expected:     "http://test-upstream$request_uri",
  3624  		},
  3625  		{
  3626  			tlsEnabled:   true,
  3627  			upstreamName: "test-upstream",
  3628  			internal:     true,
  3629  			expected:     "https://test-upstream$request_uri",
  3630  		},
  3631  	}
  3632  
  3633  	for _, test := range tests {
  3634  		result := generateProxyPass(test.tlsEnabled, test.upstreamName, test.internal, nil)
  3635  		if result != test.expected {
  3636  			t.Errorf("generateProxyPass(%v, %v, %v) returned %v but expected %v", test.tlsEnabled, test.upstreamName, test.internal, result, test.expected)
  3637  		}
  3638  	}
  3639  }
  3640  
  3641  func TestGenerateProxyPassProtocol(t *testing.T) {
  3642  	tests := []struct {
  3643  		upstream conf_v1.Upstream
  3644  		expected string
  3645  	}{
  3646  		{
  3647  			upstream: conf_v1.Upstream{},
  3648  			expected: "http",
  3649  		},
  3650  		{
  3651  			upstream: conf_v1.Upstream{
  3652  				TLS: conf_v1.UpstreamTLS{
  3653  					Enable: true,
  3654  				},
  3655  			},
  3656  			expected: "https",
  3657  		},
  3658  	}
  3659  
  3660  	for _, test := range tests {
  3661  		result := generateProxyPassProtocol(test.upstream.TLS.Enable)
  3662  		if result != test.expected {
  3663  			t.Errorf("generateProxyPassProtocol(%v) returned %v but expected %v", test.upstream.TLS.Enable, result, test.expected)
  3664  		}
  3665  	}
  3666  }
  3667  
  3668  func TestGenerateString(t *testing.T) {
  3669  	tests := []struct {
  3670  		inputS   string
  3671  		expected string
  3672  	}{
  3673  		{
  3674  			inputS:   "http_404",
  3675  			expected: "http_404",
  3676  		},
  3677  		{
  3678  			inputS:   "",
  3679  			expected: "error timeout",
  3680  		},
  3681  	}
  3682  
  3683  	for _, test := range tests {
  3684  		result := generateString(test.inputS, "error timeout")
  3685  		if result != test.expected {
  3686  			t.Errorf("generateString() return %v but expected %v", result, test.expected)
  3687  		}
  3688  	}
  3689  }
  3690  
  3691  func TestGenerateSnippets(t *testing.T) {
  3692  	tests := []struct {
  3693  		enableSnippets bool
  3694  		s              string
  3695  		defaultS       []string
  3696  		expected       []string
  3697  	}{
  3698  		{
  3699  			true,
  3700  			"test",
  3701  			[]string{},
  3702  			[]string{"test"},
  3703  		},
  3704  		{
  3705  			true,
  3706  			"",
  3707  			[]string{"default"},
  3708  			[]string{"default"},
  3709  		},
  3710  		{
  3711  			true,
  3712  			"test\none\ntwo",
  3713  			[]string{},
  3714  			[]string{"test", "one", "two"},
  3715  		},
  3716  		{
  3717  			false,
  3718  			"test",
  3719  			nil,
  3720  			nil,
  3721  		},
  3722  	}
  3723  	for _, test := range tests {
  3724  		result := generateSnippets(test.enableSnippets, test.s, test.defaultS)
  3725  		if !reflect.DeepEqual(result, test.expected) {
  3726  			t.Errorf("generateSnippets() return %v, but expected %v", result, test.expected)
  3727  		}
  3728  	}
  3729  }
  3730  
  3731  func TestGenerateBuffer(t *testing.T) {
  3732  	tests := []struct {
  3733  		inputS   *conf_v1.UpstreamBuffers
  3734  		expected string
  3735  	}{
  3736  		{
  3737  			inputS:   nil,
  3738  			expected: "8 4k",
  3739  		},
  3740  		{
  3741  			inputS:   &conf_v1.UpstreamBuffers{Number: 8, Size: "16K"},
  3742  			expected: "8 16K",
  3743  		},
  3744  	}
  3745  
  3746  	for _, test := range tests {
  3747  		result := generateBuffers(test.inputS, "8 4k")
  3748  		if result != test.expected {
  3749  			t.Errorf("generateBuffer() return %v but expected %v", result, test.expected)
  3750  		}
  3751  	}
  3752  }
  3753  
  3754  func TestGenerateLocationForProxying(t *testing.T) {
  3755  	cfgParams := ConfigParams{
  3756  		ProxyConnectTimeout:  "30s",
  3757  		ProxyReadTimeout:     "31s",
  3758  		ProxySendTimeout:     "32s",
  3759  		ClientMaxBodySize:    "1m",
  3760  		ProxyMaxTempFileSize: "1024m",
  3761  		ProxyBuffering:       true,
  3762  		ProxyBuffers:         "8 4k",
  3763  		ProxyBufferSize:      "4k",
  3764  		LocationSnippets:     []string{"# location snippet"},
  3765  	}
  3766  	path := "/"
  3767  	upstreamName := "test-upstream"
  3768  	vsLocSnippets := []string{"# vs location snippet"}
  3769  
  3770  	expected := version2.Location{
  3771  		Path:                     "/",
  3772  		Snippets:                 vsLocSnippets,
  3773  		ProxyConnectTimeout:      "30s",
  3774  		ProxyReadTimeout:         "31s",
  3775  		ProxySendTimeout:         "32s",
  3776  		ClientMaxBodySize:        "1m",
  3777  		ProxyMaxTempFileSize:     "1024m",
  3778  		ProxyBuffering:           true,
  3779  		ProxyBuffers:             "8 4k",
  3780  		ProxyBufferSize:          "4k",
  3781  		ProxyPass:                "http://test-upstream",
  3782  		ProxyNextUpstream:        "error timeout",
  3783  		ProxyNextUpstreamTimeout: "0s",
  3784  		ProxyNextUpstreamTries:   0,
  3785  		ProxyPassRequestHeaders:  true,
  3786  		ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  3787  		ServiceName:              "",
  3788  		IsVSR:                    false,
  3789  		VSRName:                  "",
  3790  		VSRNamespace:             "",
  3791  	}
  3792  
  3793  	result := generateLocationForProxying(path, upstreamName, conf_v1.Upstream{}, &cfgParams, nil, false, 0, "", nil, "", vsLocSnippets, false, "", "")
  3794  	if diff := cmp.Diff(expected, result); diff != "" {
  3795  		t.Errorf("generateLocationForProxying() mismatch (-want +got):\n%s", diff)
  3796  	}
  3797  }
  3798  
  3799  func TestGenerateReturnBlock(t *testing.T) {
  3800  	tests := []struct {
  3801  		text        string
  3802  		code        int
  3803  		defaultCode int
  3804  		expected    *version2.Return
  3805  	}{
  3806  		{
  3807  			text:        "Hello World!",
  3808  			code:        0, // Not set
  3809  			defaultCode: 200,
  3810  			expected: &version2.Return{
  3811  				Code: 200,
  3812  				Text: "Hello World!",
  3813  			},
  3814  		},
  3815  		{
  3816  			text:        "Hello World!",
  3817  			code:        400,
  3818  			defaultCode: 200,
  3819  			expected: &version2.Return{
  3820  				Code: 400,
  3821  				Text: "Hello World!",
  3822  			},
  3823  		},
  3824  	}
  3825  
  3826  	for _, test := range tests {
  3827  		result := generateReturnBlock(test.text, test.code, test.defaultCode)
  3828  		if !reflect.DeepEqual(result, test.expected) {
  3829  			t.Errorf("generateReturnBlock() returned %v but expected %v", result, test.expected)
  3830  		}
  3831  	}
  3832  }
  3833  
  3834  func TestGenerateLocationForReturn(t *testing.T) {
  3835  	tests := []struct {
  3836  		actionReturn           *conf_v1.ActionReturn
  3837  		expectedLocation       version2.Location
  3838  		expectedReturnLocation *version2.ReturnLocation
  3839  		msg                    string
  3840  	}{
  3841  		{
  3842  			actionReturn: &conf_v1.ActionReturn{
  3843  				Body: "hello",
  3844  			},
  3845  
  3846  			expectedLocation: version2.Location{
  3847  				Path:     "/",
  3848  				Snippets: []string{"# location snippet"},
  3849  				ErrorPages: []version2.ErrorPage{
  3850  					{
  3851  						Name:         "@return_1",
  3852  						Codes:        "418",
  3853  						ResponseCode: 200,
  3854  					},
  3855  				},
  3856  				ProxyInterceptErrors: true,
  3857  				InternalProxyPass:    "http://unix:/var/lib/nginx/nginx-418-server.sock",
  3858  			},
  3859  			expectedReturnLocation: &version2.ReturnLocation{
  3860  				Name:        "@return_1",
  3861  				DefaultType: "text/plain",
  3862  				Return: version2.Return{
  3863  					Code: 0,
  3864  					Text: "hello",
  3865  				},
  3866  			},
  3867  			msg: "return without code and type",
  3868  		},
  3869  		{
  3870  			actionReturn: &conf_v1.ActionReturn{
  3871  				Code: 400,
  3872  				Type: "text/html",
  3873  				Body: "hello",
  3874  			},
  3875  
  3876  			expectedLocation: version2.Location{
  3877  				Path:     "/",
  3878  				Snippets: []string{"# location snippet"},
  3879  				ErrorPages: []version2.ErrorPage{
  3880  					{
  3881  						Name:         "@return_1",
  3882  						Codes:        "418",
  3883  						ResponseCode: 400,
  3884  					},
  3885  				},
  3886  				ProxyInterceptErrors: true,
  3887  				InternalProxyPass:    "http://unix:/var/lib/nginx/nginx-418-server.sock",
  3888  			},
  3889  			expectedReturnLocation: &version2.ReturnLocation{
  3890  				Name:        "@return_1",
  3891  				DefaultType: "text/html",
  3892  				Return: version2.Return{
  3893  					Code: 0,
  3894  					Text: "hello",
  3895  				},
  3896  			},
  3897  			msg: "return with all fields defined",
  3898  		},
  3899  	}
  3900  	path := "/"
  3901  	snippets := []string{"# location snippet"}
  3902  	returnLocationIndex := 1
  3903  
  3904  	for _, test := range tests {
  3905  		location, returnLocation := generateLocationForReturn(path, snippets, test.actionReturn, returnLocationIndex)
  3906  		if !reflect.DeepEqual(location, test.expectedLocation) {
  3907  			t.Errorf("generateLocationForReturn() returned  \n%+v but expected \n%+v for the case of %s",
  3908  				location, test.expectedLocation, test.msg)
  3909  		}
  3910  		if !reflect.DeepEqual(returnLocation, test.expectedReturnLocation) {
  3911  			t.Errorf("generateLocationForReturn() returned  \n%+v but expected \n%+v for the case of %s",
  3912  				returnLocation, test.expectedReturnLocation, test.msg)
  3913  		}
  3914  	}
  3915  }
  3916  
  3917  func TestGenerateLocationForRedirect(t *testing.T) {
  3918  	tests := []struct {
  3919  		redirect *conf_v1.ActionRedirect
  3920  		expected version2.Location
  3921  		msg      string
  3922  	}{
  3923  		{
  3924  			redirect: &conf_v1.ActionRedirect{
  3925  				URL: "http://nginx.org",
  3926  			},
  3927  
  3928  			expected: version2.Location{
  3929  				Path:     "/",
  3930  				Snippets: []string{"# location snippet"},
  3931  				ErrorPages: []version2.ErrorPage{
  3932  					{
  3933  						Name:         "http://nginx.org",
  3934  						Codes:        "418",
  3935  						ResponseCode: 301,
  3936  					},
  3937  				},
  3938  				ProxyInterceptErrors: true,
  3939  				InternalProxyPass:    "http://unix:/var/lib/nginx/nginx-418-server.sock",
  3940  			},
  3941  			msg: "redirect without code",
  3942  		},
  3943  		{
  3944  			redirect: &conf_v1.ActionRedirect{
  3945  				Code: 302,
  3946  				URL:  "http://nginx.org",
  3947  			},
  3948  
  3949  			expected: version2.Location{
  3950  				Path:     "/",
  3951  				Snippets: []string{"# location snippet"},
  3952  				ErrorPages: []version2.ErrorPage{
  3953  					{
  3954  						Name:         "http://nginx.org",
  3955  						Codes:        "418",
  3956  						ResponseCode: 302,
  3957  					},
  3958  				},
  3959  				ProxyInterceptErrors: true,
  3960  				InternalProxyPass:    "http://unix:/var/lib/nginx/nginx-418-server.sock",
  3961  			},
  3962  			msg: "redirect with all fields defined",
  3963  		},
  3964  	}
  3965  
  3966  	for _, test := range tests {
  3967  		result := generateLocationForRedirect("/", []string{"# location snippet"}, test.redirect)
  3968  		if !reflect.DeepEqual(result, test.expected) {
  3969  			t.Errorf("generateLocationForReturn() returned \n%+v but expected \n%+v for the case of %s",
  3970  				result, test.expected, test.msg)
  3971  		}
  3972  	}
  3973  }
  3974  
  3975  func TestGenerateSSLConfig(t *testing.T) {
  3976  	tests := []struct {
  3977  		inputTLS         *conf_v1.TLS
  3978  		inputSecretRefs  map[string]*secrets.SecretReference
  3979  		inputCfgParams   *ConfigParams
  3980  		expectedSSL      *version2.SSL
  3981  		expectedWarnings Warnings
  3982  		msg              string
  3983  	}{
  3984  		{
  3985  			inputTLS:         nil,
  3986  			inputSecretRefs:  map[string]*secrets.SecretReference{},
  3987  			inputCfgParams:   &ConfigParams{},
  3988  			expectedSSL:      nil,
  3989  			expectedWarnings: Warnings{},
  3990  			msg:              "no TLS field",
  3991  		},
  3992  		{
  3993  			inputTLS: &conf_v1.TLS{
  3994  				Secret: "",
  3995  			},
  3996  			inputSecretRefs:  map[string]*secrets.SecretReference{},
  3997  			inputCfgParams:   &ConfigParams{},
  3998  			expectedSSL:      nil,
  3999  			expectedWarnings: Warnings{},
  4000  			msg:              "TLS field with empty secret",
  4001  		},
  4002  		{
  4003  			inputTLS: &conf_v1.TLS{
  4004  				Secret: "secret",
  4005  			},
  4006  			inputCfgParams: &ConfigParams{},
  4007  			inputSecretRefs: map[string]*secrets.SecretReference{
  4008  				"default/secret": {
  4009  					Error: errors.New("secret doesn't exist"),
  4010  				},
  4011  			},
  4012  			expectedSSL: &version2.SSL{
  4013  				HTTP2:           false,
  4014  				RejectHandshake: true,
  4015  			},
  4016  			expectedWarnings: Warnings{
  4017  				nil: []string{"TLS secret secret is invalid: secret doesn't exist"},
  4018  			},
  4019  			msg: "secret doesn't exist in the cluster with HTTPS",
  4020  		},
  4021  		{
  4022  			inputTLS: &conf_v1.TLS{
  4023  				Secret: "secret",
  4024  			},
  4025  			inputCfgParams: &ConfigParams{},
  4026  			inputSecretRefs: map[string]*secrets.SecretReference{
  4027  				"default/secret": {
  4028  					Secret: &api_v1.Secret{
  4029  						Type: secrets.SecretTypeCA,
  4030  					},
  4031  				},
  4032  			},
  4033  			expectedSSL: &version2.SSL{
  4034  				HTTP2:           false,
  4035  				RejectHandshake: true,
  4036  			},
  4037  			expectedWarnings: Warnings{
  4038  				nil: []string{"TLS secret secret is of a wrong type 'nginx.org/ca', must be 'kubernetes.io/tls'"},
  4039  			},
  4040  			msg: "wrong secret type",
  4041  		},
  4042  		{
  4043  			inputTLS: &conf_v1.TLS{
  4044  				Secret: "secret",
  4045  			},
  4046  			inputSecretRefs: map[string]*secrets.SecretReference{
  4047  				"default/secret": {
  4048  					Secret: &api_v1.Secret{
  4049  						Type: api_v1.SecretTypeTLS,
  4050  					},
  4051  					Path: "secret.pem",
  4052  				},
  4053  			},
  4054  			inputCfgParams: &ConfigParams{},
  4055  			expectedSSL: &version2.SSL{
  4056  				HTTP2:           false,
  4057  				Certificate:     "secret.pem",
  4058  				CertificateKey:  "secret.pem",
  4059  				RejectHandshake: false,
  4060  			},
  4061  			expectedWarnings: Warnings{},
  4062  			msg:              "normal case with HTTPS",
  4063  		},
  4064  	}
  4065  
  4066  	namespace := "default"
  4067  
  4068  	for _, test := range tests {
  4069  		vsc := newVirtualServerConfigurator(&ConfigParams{}, false, false, &StaticConfigParams{})
  4070  
  4071  		// it is ok to use nil as the owner
  4072  		result := vsc.generateSSLConfig(nil, test.inputTLS, namespace, test.inputSecretRefs, test.inputCfgParams)
  4073  		if !reflect.DeepEqual(result, test.expectedSSL) {
  4074  			t.Errorf("generateSSLConfig() returned %v but expected %v for the case of %s", result, test.expectedSSL, test.msg)
  4075  		}
  4076  		if !reflect.DeepEqual(vsc.warnings, test.expectedWarnings) {
  4077  			t.Errorf("generateSSLConfig() returned warnings of \n%v but expected \n%v for the case of %s", vsc.warnings, test.expectedWarnings, test.msg)
  4078  		}
  4079  	}
  4080  }
  4081  
  4082  func TestGenerateRedirectConfig(t *testing.T) {
  4083  	tests := []struct {
  4084  		inputTLS *conf_v1.TLS
  4085  		expected *version2.TLSRedirect
  4086  		msg      string
  4087  	}{
  4088  		{
  4089  			inputTLS: nil,
  4090  			expected: nil,
  4091  			msg:      "no TLS field",
  4092  		},
  4093  		{
  4094  			inputTLS: &conf_v1.TLS{
  4095  				Secret:   "secret",
  4096  				Redirect: nil,
  4097  			},
  4098  			expected: nil,
  4099  			msg:      "no redirect field",
  4100  		},
  4101  		{
  4102  			inputTLS: &conf_v1.TLS{
  4103  				Secret:   "secret",
  4104  				Redirect: &conf_v1.TLSRedirect{Enable: false},
  4105  			},
  4106  			expected: nil,
  4107  			msg:      "redirect disabled",
  4108  		},
  4109  		{
  4110  			inputTLS: &conf_v1.TLS{
  4111  				Secret: "secret",
  4112  				Redirect: &conf_v1.TLSRedirect{
  4113  					Enable: true,
  4114  				},
  4115  			},
  4116  			expected: &version2.TLSRedirect{
  4117  				Code:    301,
  4118  				BasedOn: "$scheme",
  4119  			},
  4120  			msg: "normal case with defaults",
  4121  		},
  4122  		{
  4123  			inputTLS: &conf_v1.TLS{
  4124  				Secret: "secret",
  4125  				Redirect: &conf_v1.TLSRedirect{
  4126  					Enable:  true,
  4127  					BasedOn: "x-forwarded-proto",
  4128  				},
  4129  			},
  4130  			expected: &version2.TLSRedirect{
  4131  				Code:    301,
  4132  				BasedOn: "$http_x_forwarded_proto",
  4133  			},
  4134  			msg: "normal case with BasedOn set",
  4135  		},
  4136  	}
  4137  
  4138  	for _, test := range tests {
  4139  		result := generateTLSRedirectConfig(test.inputTLS)
  4140  		if !reflect.DeepEqual(result, test.expected) {
  4141  			t.Errorf("generateTLSRedirectConfig() returned %v but expected %v for the case of %s", result, test.expected, test.msg)
  4142  		}
  4143  	}
  4144  }
  4145  
  4146  func TestGenerateTLSRedirectBasedOn(t *testing.T) {
  4147  	tests := []struct {
  4148  		basedOn  string
  4149  		expected string
  4150  	}{
  4151  		{
  4152  			basedOn:  "scheme",
  4153  			expected: "$scheme",
  4154  		},
  4155  		{
  4156  			basedOn:  "x-forwarded-proto",
  4157  			expected: "$http_x_forwarded_proto",
  4158  		},
  4159  		{
  4160  			basedOn:  "",
  4161  			expected: "$scheme",
  4162  		},
  4163  	}
  4164  	for _, test := range tests {
  4165  		result := generateTLSRedirectBasedOn(test.basedOn)
  4166  		if result != test.expected {
  4167  			t.Errorf("generateTLSRedirectBasedOn(%v) returned %v but expected %v", test.basedOn, result, test.expected)
  4168  		}
  4169  	}
  4170  }
  4171  
  4172  func TestCreateUpstreamsForPlus(t *testing.T) {
  4173  	virtualServerEx := VirtualServerEx{
  4174  		VirtualServer: &conf_v1.VirtualServer{
  4175  			ObjectMeta: meta_v1.ObjectMeta{
  4176  				Name:      "cafe",
  4177  				Namespace: "default",
  4178  			},
  4179  			Spec: conf_v1.VirtualServerSpec{
  4180  				Host: "cafe.example.com",
  4181  				Upstreams: []conf_v1.Upstream{
  4182  					{
  4183  						Name:    "tea",
  4184  						Service: "tea-svc",
  4185  						Port:    80,
  4186  					},
  4187  					{
  4188  						Name:    "test",
  4189  						Service: "test-svc",
  4190  						Port:    80,
  4191  					},
  4192  					{
  4193  						Name:        "subselector-test",
  4194  						Service:     "test-svc",
  4195  						Subselector: map[string]string{"vs": "works"},
  4196  						Port:        80,
  4197  					},
  4198  					{
  4199  						Name:    "external",
  4200  						Service: "external-svc",
  4201  						Port:    80,
  4202  					},
  4203  				},
  4204  				Routes: []conf_v1.Route{
  4205  					{
  4206  						Path: "/tea",
  4207  						Action: &conf_v1.Action{
  4208  							Pass: "tea",
  4209  						},
  4210  					},
  4211  					{
  4212  						Path:  "/coffee",
  4213  						Route: "default/coffee",
  4214  					},
  4215  					{
  4216  						Path: "/external",
  4217  						Action: &conf_v1.Action{
  4218  							Pass: "external",
  4219  						},
  4220  					},
  4221  				},
  4222  			},
  4223  		},
  4224  		Endpoints: map[string][]string{
  4225  			"default/tea-svc:80": {
  4226  				"10.0.0.20:80",
  4227  			},
  4228  			"default/test-svc:80": {},
  4229  			"default/test-svc_vs=works:80": {
  4230  				"10.0.0.30:80",
  4231  			},
  4232  			"default/coffee-svc:80": {
  4233  				"10.0.0.40:80",
  4234  			},
  4235  			"default/test-svc_vsr=works:80": {
  4236  				"10.0.0.50:80",
  4237  			},
  4238  			"default/external-svc:80": {
  4239  				"example.com:80",
  4240  			},
  4241  		},
  4242  		ExternalNameSvcs: map[string]bool{
  4243  			"default/external-svc": true,
  4244  		},
  4245  		VirtualServerRoutes: []*conf_v1.VirtualServerRoute{
  4246  			{
  4247  				ObjectMeta: meta_v1.ObjectMeta{
  4248  					Name:      "coffee",
  4249  					Namespace: "default",
  4250  				},
  4251  				Spec: conf_v1.VirtualServerRouteSpec{
  4252  					Host: "cafe.example.com",
  4253  					Upstreams: []conf_v1.Upstream{
  4254  						{
  4255  							Name:    "coffee",
  4256  							Service: "coffee-svc",
  4257  							Port:    80,
  4258  						},
  4259  						{
  4260  							Name:        "subselector-test",
  4261  							Service:     "test-svc",
  4262  							Subselector: map[string]string{"vsr": "works"},
  4263  							Port:        80,
  4264  						},
  4265  					},
  4266  					Subroutes: []conf_v1.Route{
  4267  						{
  4268  							Path: "/coffee",
  4269  							Action: &conf_v1.Action{
  4270  								Pass: "coffee",
  4271  							},
  4272  						},
  4273  						{
  4274  							Path: "/coffee/sub",
  4275  							Action: &conf_v1.Action{
  4276  								Pass: "subselector-test",
  4277  							},
  4278  						},
  4279  					},
  4280  				},
  4281  			},
  4282  		},
  4283  	}
  4284  
  4285  	expected := []version2.Upstream{
  4286  		{
  4287  			Name: "vs_default_cafe_tea",
  4288  			UpstreamLabels: version2.UpstreamLabels{
  4289  				Service:           "tea-svc",
  4290  				ResourceType:      "virtualserver",
  4291  				ResourceNamespace: "default",
  4292  				ResourceName:      "cafe",
  4293  			},
  4294  			Servers: []version2.UpstreamServer{
  4295  				{
  4296  					Address: "10.0.0.20:80",
  4297  				},
  4298  			},
  4299  		},
  4300  		{
  4301  			Name: "vs_default_cafe_test",
  4302  			UpstreamLabels: version2.UpstreamLabels{
  4303  				Service:           "test-svc",
  4304  				ResourceType:      "virtualserver",
  4305  				ResourceNamespace: "default",
  4306  				ResourceName:      "cafe",
  4307  			},
  4308  			Servers: nil,
  4309  		},
  4310  		{
  4311  			Name: "vs_default_cafe_subselector-test",
  4312  			UpstreamLabels: version2.UpstreamLabels{
  4313  				Service:           "test-svc",
  4314  				ResourceType:      "virtualserver",
  4315  				ResourceNamespace: "default",
  4316  				ResourceName:      "cafe",
  4317  			},
  4318  			Servers: []version2.UpstreamServer{
  4319  				{
  4320  					Address: "10.0.0.30:80",
  4321  				},
  4322  			},
  4323  		},
  4324  		{
  4325  			Name: "vs_default_cafe_vsr_default_coffee_coffee",
  4326  			UpstreamLabels: version2.UpstreamLabels{
  4327  				Service:           "coffee-svc",
  4328  				ResourceType:      "virtualserverroute",
  4329  				ResourceNamespace: "default",
  4330  				ResourceName:      "coffee",
  4331  			},
  4332  			Servers: []version2.UpstreamServer{
  4333  				{
  4334  					Address: "10.0.0.40:80",
  4335  				},
  4336  			},
  4337  		},
  4338  		{
  4339  			Name: "vs_default_cafe_vsr_default_coffee_subselector-test",
  4340  			UpstreamLabels: version2.UpstreamLabels{
  4341  				Service:           "test-svc",
  4342  				ResourceType:      "virtualserverroute",
  4343  				ResourceNamespace: "default",
  4344  				ResourceName:      "coffee",
  4345  			},
  4346  			Servers: []version2.UpstreamServer{
  4347  				{
  4348  					Address: "10.0.0.50:80",
  4349  				},
  4350  			},
  4351  		},
  4352  	}
  4353  
  4354  	result := createUpstreamsForPlus(&virtualServerEx, &ConfigParams{}, &StaticConfigParams{})
  4355  	if !reflect.DeepEqual(result, expected) {
  4356  		t.Errorf("createUpstreamsForPlus returned \n%v but expected \n%v", result, expected)
  4357  	}
  4358  }
  4359  
  4360  func TestCreateUpstreamServersConfigForPlus(t *testing.T) {
  4361  	upstream := version2.Upstream{
  4362  		Servers: []version2.UpstreamServer{
  4363  			{
  4364  				Address: "10.0.0.20:80",
  4365  			},
  4366  		},
  4367  		MaxFails:    21,
  4368  		MaxConns:    16,
  4369  		FailTimeout: "30s",
  4370  		SlowStart:   "50s",
  4371  	}
  4372  
  4373  	expected := nginx.ServerConfig{
  4374  		MaxFails:    21,
  4375  		MaxConns:    16,
  4376  		FailTimeout: "30s",
  4377  		SlowStart:   "50s",
  4378  	}
  4379  
  4380  	result := createUpstreamServersConfigForPlus(upstream)
  4381  	if !reflect.DeepEqual(result, expected) {
  4382  		t.Errorf("createUpstreamServersConfigForPlus returned %v but expected %v", result, expected)
  4383  	}
  4384  }
  4385  
  4386  func TestCreateUpstreamServersConfigForPlusNoUpstreams(t *testing.T) {
  4387  	noUpstream := version2.Upstream{}
  4388  	expected := nginx.ServerConfig{}
  4389  
  4390  	result := createUpstreamServersConfigForPlus(noUpstream)
  4391  	if !reflect.DeepEqual(result, expected) {
  4392  		t.Errorf("createUpstreamServersConfigForPlus returned %v but expected %v", result, expected)
  4393  	}
  4394  }
  4395  
  4396  func TestGenerateSplits(t *testing.T) {
  4397  	originalPath := "/path"
  4398  	splits := []conf_v1.Split{
  4399  		{
  4400  			Weight: 90,
  4401  			Action: &conf_v1.Action{
  4402  				Proxy: &conf_v1.ActionProxy{
  4403  					Upstream:    "coffee-v1",
  4404  					RewritePath: "/rewrite",
  4405  				},
  4406  			},
  4407  		},
  4408  		{
  4409  			Weight: 9,
  4410  			Action: &conf_v1.Action{
  4411  				Pass: "coffee-v2",
  4412  			},
  4413  		},
  4414  		{
  4415  			Weight: 1,
  4416  			Action: &conf_v1.Action{
  4417  				Return: &conf_v1.ActionReturn{
  4418  					Body: "hello",
  4419  				},
  4420  			},
  4421  		},
  4422  	}
  4423  
  4424  	virtualServer := conf_v1.VirtualServer{
  4425  		ObjectMeta: meta_v1.ObjectMeta{
  4426  			Name:      "cafe",
  4427  			Namespace: "default",
  4428  		},
  4429  	}
  4430  	upstreamNamer := newUpstreamNamerForVirtualServer(&virtualServer)
  4431  	variableNamer := newVariableNamer(&virtualServer)
  4432  	scIndex := 1
  4433  	cfgParams := ConfigParams{}
  4434  	crUpstreams := map[string]conf_v1.Upstream{
  4435  		"vs_default_cafe_coffee-v1": {
  4436  			Service: "coffee-v1",
  4437  		},
  4438  		"vs_default_cafe_coffee-v2": {
  4439  			Service: "coffee-v2",
  4440  		},
  4441  	}
  4442  	locSnippet := "# location snippet"
  4443  	enableSnippets := true
  4444  	errorPages := []conf_v1.ErrorPage{
  4445  		{
  4446  			Codes: []int{400, 500},
  4447  			Return: &conf_v1.ErrorPageReturn{
  4448  				ActionReturn: conf_v1.ActionReturn{
  4449  					Code: 200,
  4450  					Type: "application/json",
  4451  					Body: `{\"message\": \"ok\"}`,
  4452  				},
  4453  				Headers: []conf_v1.Header{
  4454  					{
  4455  						Name:  "Set-Cookie",
  4456  						Value: "cookie1=value",
  4457  					},
  4458  				},
  4459  			},
  4460  			Redirect: nil,
  4461  		},
  4462  		{
  4463  			Codes:  []int{500, 502},
  4464  			Return: nil,
  4465  			Redirect: &conf_v1.ErrorPageRedirect{
  4466  				ActionRedirect: conf_v1.ActionRedirect{
  4467  					URL:  "http://nginx.com",
  4468  					Code: 301,
  4469  				},
  4470  			},
  4471  		},
  4472  	}
  4473  
  4474  	expectedSplitClient := version2.SplitClient{
  4475  		Source:   "$request_id",
  4476  		Variable: "$vs_default_cafe_splits_1",
  4477  		Distributions: []version2.Distribution{
  4478  			{
  4479  				Weight: "90%",
  4480  				Value:  "/internal_location_splits_1_split_0",
  4481  			},
  4482  			{
  4483  				Weight: "9%",
  4484  				Value:  "/internal_location_splits_1_split_1",
  4485  			},
  4486  			{
  4487  				Weight: "1%",
  4488  				Value:  "/internal_location_splits_1_split_2",
  4489  			},
  4490  		},
  4491  	}
  4492  	expectedLocations := []version2.Location{
  4493  		{
  4494  			Path:      "/internal_location_splits_1_split_0",
  4495  			ProxyPass: "http://vs_default_cafe_coffee-v1",
  4496  			Rewrites: []string{
  4497  				"^ $request_uri",
  4498  				fmt.Sprintf(`"^%v(.*)$" "/rewrite$1" break`, originalPath),
  4499  			},
  4500  			ProxyNextUpstream:        "error timeout",
  4501  			ProxyNextUpstreamTimeout: "0s",
  4502  			ProxyNextUpstreamTries:   0,
  4503  			ProxyInterceptErrors:     true,
  4504  			Internal:                 true,
  4505  			ErrorPages: []version2.ErrorPage{
  4506  				{
  4507  					Name:         "@error_page_0_0",
  4508  					Codes:        "400 500",
  4509  					ResponseCode: 200,
  4510  				},
  4511  				{
  4512  					Name:         "http://nginx.com",
  4513  					Codes:        "500 502",
  4514  					ResponseCode: 301,
  4515  				},
  4516  			},
  4517  			ProxySSLName:            "coffee-v1.default.svc",
  4518  			ProxyPassRequestHeaders: true,
  4519  			ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  4520  			Snippets:                []string{locSnippet},
  4521  			ServiceName:             "coffee-v1",
  4522  			IsVSR:                   true,
  4523  			VSRName:                 "coffee",
  4524  			VSRNamespace:            "default",
  4525  		},
  4526  		{
  4527  			Path:                     "/internal_location_splits_1_split_1",
  4528  			ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  4529  			ProxyNextUpstream:        "error timeout",
  4530  			ProxyNextUpstreamTimeout: "0s",
  4531  			ProxyNextUpstreamTries:   0,
  4532  			ProxyInterceptErrors:     true,
  4533  			Internal:                 true,
  4534  			ErrorPages: []version2.ErrorPage{
  4535  				{
  4536  					Name:         "@error_page_0_0",
  4537  					Codes:        "400 500",
  4538  					ResponseCode: 200,
  4539  				},
  4540  				{
  4541  					Name:         "http://nginx.com",
  4542  					Codes:        "500 502",
  4543  					ResponseCode: 301,
  4544  				},
  4545  			},
  4546  			ProxySSLName:            "coffee-v2.default.svc",
  4547  			ProxyPassRequestHeaders: true,
  4548  			ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  4549  			Snippets:                []string{locSnippet},
  4550  			ServiceName:             "coffee-v2",
  4551  			IsVSR:                   true,
  4552  			VSRName:                 "coffee",
  4553  			VSRNamespace:            "default",
  4554  		},
  4555  		{
  4556  			Path:                 "/internal_location_splits_1_split_2",
  4557  			ProxyInterceptErrors: true,
  4558  			ErrorPages: []version2.ErrorPage{
  4559  				{
  4560  					Name:         "@return_1",
  4561  					Codes:        "418",
  4562  					ResponseCode: 200,
  4563  				},
  4564  			},
  4565  			InternalProxyPass: "http://unix:/var/lib/nginx/nginx-418-server.sock",
  4566  		},
  4567  	}
  4568  	expectedReturnLocations := []version2.ReturnLocation{
  4569  		{
  4570  			Name:        "@return_1",
  4571  			DefaultType: "text/plain",
  4572  			Return: version2.Return{
  4573  				Code: 0,
  4574  				Text: "hello",
  4575  			},
  4576  		},
  4577  	}
  4578  	returnLocationIndex := 1
  4579  
  4580  	resultSplitClient, resultLocations, resultReturnLocations := generateSplits(
  4581  		splits,
  4582  		upstreamNamer,
  4583  		crUpstreams,
  4584  		variableNamer,
  4585  		scIndex,
  4586  		&cfgParams,
  4587  		errorPages,
  4588  		0,
  4589  		originalPath,
  4590  		locSnippet,
  4591  		enableSnippets,
  4592  		returnLocationIndex,
  4593  		true,
  4594  		"coffee",
  4595  		"default",
  4596  	)
  4597  	if !reflect.DeepEqual(resultSplitClient, expectedSplitClient) {
  4598  		t.Errorf("generateSplits() returned \n%+v but expected \n%+v", resultSplitClient, expectedSplitClient)
  4599  	}
  4600  	if !reflect.DeepEqual(resultLocations, expectedLocations) {
  4601  		t.Errorf("generateSplits() returned \n%+v but expected \n%+v", resultLocations, expectedLocations)
  4602  	}
  4603  	if !reflect.DeepEqual(resultReturnLocations, expectedReturnLocations) {
  4604  		t.Errorf("generateSplits() returned \n%+v but expected \n%+v", resultReturnLocations, expectedReturnLocations)
  4605  	}
  4606  }
  4607  
  4608  func TestGenerateDefaultSplitsConfig(t *testing.T) {
  4609  	route := conf_v1.Route{
  4610  		Path: "/",
  4611  		Splits: []conf_v1.Split{
  4612  			{
  4613  				Weight: 90,
  4614  				Action: &conf_v1.Action{
  4615  					Pass: "coffee-v1",
  4616  				},
  4617  			},
  4618  			{
  4619  				Weight: 10,
  4620  				Action: &conf_v1.Action{
  4621  					Pass: "coffee-v2",
  4622  				},
  4623  			},
  4624  		},
  4625  	}
  4626  	virtualServer := conf_v1.VirtualServer{
  4627  		ObjectMeta: meta_v1.ObjectMeta{
  4628  			Name:      "cafe",
  4629  			Namespace: "default",
  4630  		},
  4631  	}
  4632  	upstreamNamer := newUpstreamNamerForVirtualServer(&virtualServer)
  4633  	variableNamer := newVariableNamer(&virtualServer)
  4634  	index := 1
  4635  
  4636  	expected := routingCfg{
  4637  		SplitClients: []version2.SplitClient{
  4638  			{
  4639  				Source:   "$request_id",
  4640  				Variable: "$vs_default_cafe_splits_1",
  4641  				Distributions: []version2.Distribution{
  4642  					{
  4643  						Weight: "90%",
  4644  						Value:  "/internal_location_splits_1_split_0",
  4645  					},
  4646  					{
  4647  						Weight: "10%",
  4648  						Value:  "/internal_location_splits_1_split_1",
  4649  					},
  4650  				},
  4651  			},
  4652  		},
  4653  		Locations: []version2.Location{
  4654  			{
  4655  				Path:                     "/internal_location_splits_1_split_0",
  4656  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  4657  				ProxyNextUpstream:        "error timeout",
  4658  				ProxyNextUpstreamTimeout: "0s",
  4659  				ProxyNextUpstreamTries:   0,
  4660  				Internal:                 true,
  4661  				ProxySSLName:             "coffee-v1.default.svc",
  4662  				ProxyPassRequestHeaders:  true,
  4663  				ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  4664  				ServiceName:              "coffee-v1",
  4665  				IsVSR:                    true,
  4666  				VSRName:                  "coffee",
  4667  				VSRNamespace:             "default",
  4668  			},
  4669  			{
  4670  				Path:                     "/internal_location_splits_1_split_1",
  4671  				ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  4672  				ProxyNextUpstream:        "error timeout",
  4673  				ProxyNextUpstreamTimeout: "0s",
  4674  				ProxyNextUpstreamTries:   0,
  4675  				Internal:                 true,
  4676  				ProxySSLName:             "coffee-v2.default.svc",
  4677  				ProxyPassRequestHeaders:  true,
  4678  				ProxySetHeaders:          []version2.Header{{Name: "Host", Value: "$host"}},
  4679  				ServiceName:              "coffee-v2",
  4680  				IsVSR:                    true,
  4681  				VSRName:                  "coffee",
  4682  				VSRNamespace:             "default",
  4683  			},
  4684  		},
  4685  		InternalRedirectLocation: version2.InternalRedirectLocation{
  4686  			Path:        "/",
  4687  			Destination: "$vs_default_cafe_splits_1",
  4688  		},
  4689  	}
  4690  
  4691  	cfgParams := ConfigParams{}
  4692  	locSnippet := ""
  4693  	enableSnippets := false
  4694  	crUpstreams := map[string]conf_v1.Upstream{
  4695  		"vs_default_cafe_coffee-v1": {
  4696  			Service: "coffee-v1",
  4697  		},
  4698  		"vs_default_cafe_coffee-v2": {
  4699  			Service: "coffee-v2",
  4700  		},
  4701  	}
  4702  
  4703  	result := generateDefaultSplitsConfig(route, upstreamNamer, crUpstreams, variableNamer, index, &cfgParams,
  4704  		route.ErrorPages, 0, "", locSnippet, enableSnippets, 0, true, "coffee", "default")
  4705  	if !reflect.DeepEqual(result, expected) {
  4706  		t.Errorf("generateDefaultSplitsConfig() returned \n%+v but expected \n%+v", result, expected)
  4707  	}
  4708  }
  4709  
  4710  func TestGenerateMatchesConfig(t *testing.T) {
  4711  	route := conf_v1.Route{
  4712  		Path: "/",
  4713  		Matches: []conf_v1.Match{
  4714  			{
  4715  				Conditions: []conf_v1.Condition{
  4716  					{
  4717  						Header: "x-version",
  4718  						Value:  "v1",
  4719  					},
  4720  					{
  4721  						Cookie: "user",
  4722  						Value:  "john",
  4723  					},
  4724  					{
  4725  						Argument: "answer",
  4726  						Value:    "yes",
  4727  					},
  4728  					{
  4729  						Variable: "$request_method",
  4730  						Value:    "GET",
  4731  					},
  4732  				},
  4733  				Action: &conf_v1.Action{
  4734  					Pass: "coffee-v1",
  4735  				},
  4736  			},
  4737  			{
  4738  				Conditions: []conf_v1.Condition{
  4739  					{
  4740  						Header: "x-version",
  4741  						Value:  "v2",
  4742  					},
  4743  					{
  4744  						Cookie: "user",
  4745  						Value:  "paul",
  4746  					},
  4747  					{
  4748  						Argument: "answer",
  4749  						Value:    "no",
  4750  					},
  4751  					{
  4752  						Variable: "$request_method",
  4753  						Value:    "POST",
  4754  					},
  4755  				},
  4756  				Splits: []conf_v1.Split{
  4757  					{
  4758  						Weight: 90,
  4759  						Action: &conf_v1.Action{
  4760  							Pass: "coffee-v1",
  4761  						},
  4762  					},
  4763  					{
  4764  						Weight: 10,
  4765  						Action: &conf_v1.Action{
  4766  							Pass: "coffee-v2",
  4767  						},
  4768  					},
  4769  				},
  4770  			},
  4771  		},
  4772  		Action: &conf_v1.Action{
  4773  			Pass: "tea",
  4774  		},
  4775  	}
  4776  	virtualServer := conf_v1.VirtualServer{
  4777  		ObjectMeta: meta_v1.ObjectMeta{
  4778  			Name:      "cafe",
  4779  			Namespace: "default",
  4780  		},
  4781  	}
  4782  	errorPages := []conf_v1.ErrorPage{
  4783  		{
  4784  			Codes: []int{400, 500},
  4785  			Return: &conf_v1.ErrorPageReturn{
  4786  				ActionReturn: conf_v1.ActionReturn{
  4787  					Code: 200,
  4788  					Type: "application/json",
  4789  					Body: `{\"message\": \"ok\"}`,
  4790  				},
  4791  				Headers: []conf_v1.Header{
  4792  					{
  4793  						Name:  "Set-Cookie",
  4794  						Value: "cookie1=value",
  4795  					},
  4796  				},
  4797  			},
  4798  			Redirect: nil,
  4799  		},
  4800  		{
  4801  			Codes:  []int{500, 502},
  4802  			Return: nil,
  4803  			Redirect: &conf_v1.ErrorPageRedirect{
  4804  				ActionRedirect: conf_v1.ActionRedirect{
  4805  					URL:  "http://nginx.com",
  4806  					Code: 301,
  4807  				},
  4808  			},
  4809  		},
  4810  	}
  4811  	upstreamNamer := newUpstreamNamerForVirtualServer(&virtualServer)
  4812  	variableNamer := newVariableNamer(&virtualServer)
  4813  	index := 1
  4814  	scIndex := 2
  4815  
  4816  	expected := routingCfg{
  4817  		Maps: []version2.Map{
  4818  			{
  4819  				Source:   "$http_x_version",
  4820  				Variable: "$vs_default_cafe_matches_1_match_0_cond_0",
  4821  				Parameters: []version2.Parameter{
  4822  					{
  4823  						Value:  `"v1"`,
  4824  						Result: "$vs_default_cafe_matches_1_match_0_cond_1",
  4825  					},
  4826  					{
  4827  						Value:  "default",
  4828  						Result: "0",
  4829  					},
  4830  				},
  4831  			},
  4832  			{
  4833  				Source:   "$cookie_user",
  4834  				Variable: "$vs_default_cafe_matches_1_match_0_cond_1",
  4835  				Parameters: []version2.Parameter{
  4836  					{
  4837  						Value:  `"john"`,
  4838  						Result: "$vs_default_cafe_matches_1_match_0_cond_2",
  4839  					},
  4840  					{
  4841  						Value:  "default",
  4842  						Result: "0",
  4843  					},
  4844  				},
  4845  			},
  4846  			{
  4847  				Source:   "$arg_answer",
  4848  				Variable: "$vs_default_cafe_matches_1_match_0_cond_2",
  4849  				Parameters: []version2.Parameter{
  4850  					{
  4851  						Value:  `"yes"`,
  4852  						Result: "$vs_default_cafe_matches_1_match_0_cond_3",
  4853  					},
  4854  					{
  4855  						Value:  "default",
  4856  						Result: "0",
  4857  					},
  4858  				},
  4859  			},
  4860  			{
  4861  				Source:   "$request_method",
  4862  				Variable: "$vs_default_cafe_matches_1_match_0_cond_3",
  4863  				Parameters: []version2.Parameter{
  4864  					{
  4865  						Value:  `"GET"`,
  4866  						Result: "1",
  4867  					},
  4868  					{
  4869  						Value:  "default",
  4870  						Result: "0",
  4871  					},
  4872  				},
  4873  			},
  4874  			{
  4875  				Source:   "$http_x_version",
  4876  				Variable: "$vs_default_cafe_matches_1_match_1_cond_0",
  4877  				Parameters: []version2.Parameter{
  4878  					{
  4879  						Value:  `"v2"`,
  4880  						Result: "$vs_default_cafe_matches_1_match_1_cond_1",
  4881  					},
  4882  					{
  4883  						Value:  "default",
  4884  						Result: "0",
  4885  					},
  4886  				},
  4887  			},
  4888  			{
  4889  				Source:   "$cookie_user",
  4890  				Variable: "$vs_default_cafe_matches_1_match_1_cond_1",
  4891  				Parameters: []version2.Parameter{
  4892  					{
  4893  						Value:  `"paul"`,
  4894  						Result: "$vs_default_cafe_matches_1_match_1_cond_2",
  4895  					},
  4896  					{
  4897  						Value:  "default",
  4898  						Result: "0",
  4899  					},
  4900  				},
  4901  			},
  4902  			{
  4903  				Source:   "$arg_answer",
  4904  				Variable: "$vs_default_cafe_matches_1_match_1_cond_2",
  4905  				Parameters: []version2.Parameter{
  4906  					{
  4907  						Value:  `"no"`,
  4908  						Result: "$vs_default_cafe_matches_1_match_1_cond_3",
  4909  					},
  4910  					{
  4911  						Value:  "default",
  4912  						Result: "0",
  4913  					},
  4914  				},
  4915  			},
  4916  			{
  4917  				Source:   "$request_method",
  4918  				Variable: "$vs_default_cafe_matches_1_match_1_cond_3",
  4919  				Parameters: []version2.Parameter{
  4920  					{
  4921  						Value:  `"POST"`,
  4922  						Result: "1",
  4923  					},
  4924  					{
  4925  						Value:  "default",
  4926  						Result: "0",
  4927  					},
  4928  				},
  4929  			},
  4930  			{
  4931  				Source:   "$vs_default_cafe_matches_1_match_0_cond_0$vs_default_cafe_matches_1_match_1_cond_0",
  4932  				Variable: "$vs_default_cafe_matches_1",
  4933  				Parameters: []version2.Parameter{
  4934  					{
  4935  						Value:  "~^1",
  4936  						Result: "/internal_location_matches_1_match_0",
  4937  					},
  4938  					{
  4939  						Value:  "~^01",
  4940  						Result: "$vs_default_cafe_splits_2",
  4941  					},
  4942  					{
  4943  						Value:  "default",
  4944  						Result: "/internal_location_matches_1_default",
  4945  					},
  4946  				},
  4947  			},
  4948  		},
  4949  		Locations: []version2.Location{
  4950  			{
  4951  				Path:                     "/internal_location_matches_1_match_0",
  4952  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  4953  				ProxyNextUpstream:        "error timeout",
  4954  				ProxyNextUpstreamTimeout: "0s",
  4955  				ProxyNextUpstreamTries:   0,
  4956  				ProxyInterceptErrors:     true,
  4957  				Internal:                 true,
  4958  				ErrorPages: []version2.ErrorPage{
  4959  					{
  4960  						Name:         "@error_page_2_0",
  4961  						Codes:        "400 500",
  4962  						ResponseCode: 200,
  4963  					},
  4964  					{
  4965  						Name:         "http://nginx.com",
  4966  						Codes:        "500 502",
  4967  						ResponseCode: 301,
  4968  					},
  4969  				},
  4970  				ProxySSLName:            "coffee-v1.default.svc",
  4971  				ProxyPassRequestHeaders: true,
  4972  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  4973  				ServiceName:             "coffee-v1",
  4974  				IsVSR:                   false,
  4975  				VSRName:                 "",
  4976  				VSRNamespace:            "",
  4977  			},
  4978  			{
  4979  				Path:                     "/internal_location_splits_2_split_0",
  4980  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  4981  				ProxyNextUpstream:        "error timeout",
  4982  				ProxyNextUpstreamTimeout: "0s",
  4983  				ProxyNextUpstreamTries:   0,
  4984  				ProxyInterceptErrors:     true,
  4985  				Internal:                 true,
  4986  				ErrorPages: []version2.ErrorPage{
  4987  					{
  4988  						Name:         "@error_page_2_0",
  4989  						Codes:        "400 500",
  4990  						ResponseCode: 200,
  4991  					},
  4992  					{
  4993  						Name:         "http://nginx.com",
  4994  						Codes:        "500 502",
  4995  						ResponseCode: 301,
  4996  					},
  4997  				},
  4998  				ProxySSLName:            "coffee-v1.default.svc",
  4999  				ProxyPassRequestHeaders: true,
  5000  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5001  				ServiceName:             "coffee-v1",
  5002  				IsVSR:                   false,
  5003  				VSRName:                 "",
  5004  				VSRNamespace:            "",
  5005  			},
  5006  			{
  5007  				Path:                     "/internal_location_splits_2_split_1",
  5008  				ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  5009  				ProxyNextUpstream:        "error timeout",
  5010  				ProxyNextUpstreamTimeout: "0s",
  5011  				ProxyNextUpstreamTries:   0,
  5012  				ProxyInterceptErrors:     true,
  5013  				Internal:                 true,
  5014  				ErrorPages: []version2.ErrorPage{
  5015  					{
  5016  						Name:         "@error_page_2_0",
  5017  						Codes:        "400 500",
  5018  						ResponseCode: 200,
  5019  					},
  5020  					{
  5021  						Name:         "http://nginx.com",
  5022  						Codes:        "500 502",
  5023  						ResponseCode: 301,
  5024  					},
  5025  				},
  5026  				ProxySSLName:            "coffee-v2.default.svc",
  5027  				ProxyPassRequestHeaders: true,
  5028  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5029  				ServiceName:             "coffee-v2",
  5030  				IsVSR:                   false,
  5031  				VSRName:                 "",
  5032  				VSRNamespace:            "",
  5033  			},
  5034  			{
  5035  				Path:                     "/internal_location_matches_1_default",
  5036  				ProxyPass:                "http://vs_default_cafe_tea$request_uri",
  5037  				ProxyNextUpstream:        "error timeout",
  5038  				ProxyNextUpstreamTimeout: "0s",
  5039  				ProxyNextUpstreamTries:   0,
  5040  				ProxyInterceptErrors:     true,
  5041  				Internal:                 true,
  5042  				ErrorPages: []version2.ErrorPage{
  5043  					{
  5044  						Name:         "@error_page_2_0",
  5045  						Codes:        "400 500",
  5046  						ResponseCode: 200,
  5047  					},
  5048  					{
  5049  						Name:         "http://nginx.com",
  5050  						Codes:        "500 502",
  5051  						ResponseCode: 301,
  5052  					},
  5053  				},
  5054  				ProxySSLName:            "tea.default.svc",
  5055  				ProxyPassRequestHeaders: true,
  5056  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5057  				ServiceName:             "tea",
  5058  				IsVSR:                   false,
  5059  				VSRName:                 "",
  5060  				VSRNamespace:            "",
  5061  			},
  5062  		},
  5063  		InternalRedirectLocation: version2.InternalRedirectLocation{
  5064  			Path:        "/",
  5065  			Destination: "$vs_default_cafe_matches_1",
  5066  		},
  5067  		SplitClients: []version2.SplitClient{
  5068  			{
  5069  				Source:   "$request_id",
  5070  				Variable: "$vs_default_cafe_splits_2",
  5071  				Distributions: []version2.Distribution{
  5072  					{
  5073  						Weight: "90%",
  5074  						Value:  "/internal_location_splits_2_split_0",
  5075  					},
  5076  					{
  5077  						Weight: "10%",
  5078  						Value:  "/internal_location_splits_2_split_1",
  5079  					},
  5080  				},
  5081  			},
  5082  		},
  5083  	}
  5084  
  5085  	cfgParams := ConfigParams{}
  5086  	enableSnippets := false
  5087  	locSnippets := ""
  5088  	crUpstreams := map[string]conf_v1.Upstream{
  5089  		"vs_default_cafe_coffee-v1": {Service: "coffee-v1"},
  5090  		"vs_default_cafe_coffee-v2": {Service: "coffee-v2"},
  5091  		"vs_default_cafe_tea":       {Service: "tea"},
  5092  	}
  5093  
  5094  	result := generateMatchesConfig(
  5095  		route,
  5096  		upstreamNamer,
  5097  		crUpstreams,
  5098  		variableNamer,
  5099  		index,
  5100  		scIndex,
  5101  		&cfgParams,
  5102  		errorPages,
  5103  		2,
  5104  		locSnippets,
  5105  		enableSnippets,
  5106  		0,
  5107  		false,
  5108  		"",
  5109  		"",
  5110  	)
  5111  	if !reflect.DeepEqual(result, expected) {
  5112  		t.Errorf("generateMatchesConfig() returned \n%+v but expected \n%+v", result, expected)
  5113  	}
  5114  }
  5115  
  5116  func TestGenerateMatchesConfigWithMultipleSplits(t *testing.T) {
  5117  	route := conf_v1.Route{
  5118  		Path: "/",
  5119  		Matches: []conf_v1.Match{
  5120  			{
  5121  				Conditions: []conf_v1.Condition{
  5122  					{
  5123  						Header: "x-version",
  5124  						Value:  "v1",
  5125  					},
  5126  				},
  5127  				Splits: []conf_v1.Split{
  5128  					{
  5129  						Weight: 30,
  5130  						Action: &conf_v1.Action{
  5131  							Pass: "coffee-v1",
  5132  						},
  5133  					},
  5134  					{
  5135  						Weight: 70,
  5136  						Action: &conf_v1.Action{
  5137  							Pass: "coffee-v2",
  5138  						},
  5139  					},
  5140  				},
  5141  			},
  5142  			{
  5143  				Conditions: []conf_v1.Condition{
  5144  					{
  5145  						Header: "x-version",
  5146  						Value:  "v2",
  5147  					},
  5148  				},
  5149  				Splits: []conf_v1.Split{
  5150  					{
  5151  						Weight: 90,
  5152  						Action: &conf_v1.Action{
  5153  							Pass: "coffee-v2",
  5154  						},
  5155  					},
  5156  					{
  5157  						Weight: 10,
  5158  						Action: &conf_v1.Action{
  5159  							Pass: "coffee-v1",
  5160  						},
  5161  					},
  5162  				},
  5163  			},
  5164  		},
  5165  		Splits: []conf_v1.Split{
  5166  			{
  5167  				Weight: 99,
  5168  				Action: &conf_v1.Action{
  5169  					Pass: "coffee-v1",
  5170  				},
  5171  			},
  5172  			{
  5173  				Weight: 1,
  5174  				Action: &conf_v1.Action{
  5175  					Pass: "coffee-v2",
  5176  				},
  5177  			},
  5178  		},
  5179  	}
  5180  	virtualServer := conf_v1.VirtualServer{
  5181  		ObjectMeta: meta_v1.ObjectMeta{
  5182  			Name:      "cafe",
  5183  			Namespace: "default",
  5184  		},
  5185  	}
  5186  	upstreamNamer := newUpstreamNamerForVirtualServer(&virtualServer)
  5187  	variableNamer := newVariableNamer(&virtualServer)
  5188  	index := 1
  5189  	scIndex := 2
  5190  	errorPages := []conf_v1.ErrorPage{
  5191  		{
  5192  			Codes: []int{400, 500},
  5193  			Return: &conf_v1.ErrorPageReturn{
  5194  				ActionReturn: conf_v1.ActionReturn{
  5195  					Code: 200,
  5196  					Type: "application/json",
  5197  					Body: `{\"message\": \"ok\"}`,
  5198  				},
  5199  				Headers: []conf_v1.Header{
  5200  					{
  5201  						Name:  "Set-Cookie",
  5202  						Value: "cookie1=value",
  5203  					},
  5204  				},
  5205  			},
  5206  			Redirect: nil,
  5207  		},
  5208  		{
  5209  			Codes:  []int{500, 502},
  5210  			Return: nil,
  5211  			Redirect: &conf_v1.ErrorPageRedirect{
  5212  				ActionRedirect: conf_v1.ActionRedirect{
  5213  					URL:  "http://nginx.com",
  5214  					Code: 301,
  5215  				},
  5216  			},
  5217  		},
  5218  	}
  5219  
  5220  	expected := routingCfg{
  5221  		Maps: []version2.Map{
  5222  			{
  5223  				Source:   "$http_x_version",
  5224  				Variable: "$vs_default_cafe_matches_1_match_0_cond_0",
  5225  				Parameters: []version2.Parameter{
  5226  					{
  5227  						Value:  `"v1"`,
  5228  						Result: "1",
  5229  					},
  5230  					{
  5231  						Value:  "default",
  5232  						Result: "0",
  5233  					},
  5234  				},
  5235  			},
  5236  			{
  5237  				Source:   "$http_x_version",
  5238  				Variable: "$vs_default_cafe_matches_1_match_1_cond_0",
  5239  				Parameters: []version2.Parameter{
  5240  					{
  5241  						Value:  `"v2"`,
  5242  						Result: "1",
  5243  					},
  5244  					{
  5245  						Value:  "default",
  5246  						Result: "0",
  5247  					},
  5248  				},
  5249  			},
  5250  			{
  5251  				Source:   "$vs_default_cafe_matches_1_match_0_cond_0$vs_default_cafe_matches_1_match_1_cond_0",
  5252  				Variable: "$vs_default_cafe_matches_1",
  5253  				Parameters: []version2.Parameter{
  5254  					{
  5255  						Value:  "~^1",
  5256  						Result: "$vs_default_cafe_splits_2",
  5257  					},
  5258  					{
  5259  						Value:  "~^01",
  5260  						Result: "$vs_default_cafe_splits_3",
  5261  					},
  5262  					{
  5263  						Value:  "default",
  5264  						Result: "$vs_default_cafe_splits_4",
  5265  					},
  5266  				},
  5267  			},
  5268  		},
  5269  		Locations: []version2.Location{
  5270  			{
  5271  				Path:                     "/internal_location_splits_2_split_0",
  5272  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  5273  				ProxyNextUpstream:        "error timeout",
  5274  				ProxyNextUpstreamTimeout: "0s",
  5275  				ProxyNextUpstreamTries:   0,
  5276  				Internal:                 true,
  5277  				ErrorPages: []version2.ErrorPage{
  5278  					{
  5279  						Name:         "@error_page_0_0",
  5280  						Codes:        "400 500",
  5281  						ResponseCode: 200,
  5282  					},
  5283  					{
  5284  						Name:         "http://nginx.com",
  5285  						Codes:        "500 502",
  5286  						ResponseCode: 301,
  5287  					},
  5288  				},
  5289  				ProxyInterceptErrors:    true,
  5290  				ProxySSLName:            "coffee-v1.default.svc",
  5291  				ProxyPassRequestHeaders: true,
  5292  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5293  				ServiceName:             "coffee-v1",
  5294  				IsVSR:                   true,
  5295  				VSRName:                 "coffee",
  5296  				VSRNamespace:            "default",
  5297  			},
  5298  			{
  5299  				Path:                     "/internal_location_splits_2_split_1",
  5300  				ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  5301  				ProxyNextUpstream:        "error timeout",
  5302  				ProxyNextUpstreamTimeout: "0s",
  5303  				ProxyNextUpstreamTries:   0,
  5304  				Internal:                 true,
  5305  				ErrorPages: []version2.ErrorPage{
  5306  					{
  5307  						Name:         "@error_page_0_0",
  5308  						Codes:        "400 500",
  5309  						ResponseCode: 200,
  5310  					},
  5311  					{
  5312  						Name:         "http://nginx.com",
  5313  						Codes:        "500 502",
  5314  						ResponseCode: 301,
  5315  					},
  5316  				},
  5317  				ProxyInterceptErrors:    true,
  5318  				ProxySSLName:            "coffee-v2.default.svc",
  5319  				ProxyPassRequestHeaders: true,
  5320  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5321  				ServiceName:             "coffee-v2",
  5322  				IsVSR:                   true,
  5323  				VSRName:                 "coffee",
  5324  				VSRNamespace:            "default",
  5325  			},
  5326  			{
  5327  				Path:                     "/internal_location_splits_3_split_0",
  5328  				ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  5329  				ProxyNextUpstream:        "error timeout",
  5330  				ProxyNextUpstreamTimeout: "0s",
  5331  				ProxyNextUpstreamTries:   0,
  5332  				Internal:                 true,
  5333  				ErrorPages: []version2.ErrorPage{
  5334  					{
  5335  						Name:         "@error_page_0_0",
  5336  						Codes:        "400 500",
  5337  						ResponseCode: 200,
  5338  					},
  5339  					{
  5340  						Name:         "http://nginx.com",
  5341  						Codes:        "500 502",
  5342  						ResponseCode: 301,
  5343  					},
  5344  				},
  5345  				ProxyInterceptErrors:    true,
  5346  				ProxySSLName:            "coffee-v2.default.svc",
  5347  				ProxyPassRequestHeaders: true,
  5348  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5349  				ServiceName:             "coffee-v2",
  5350  				IsVSR:                   true,
  5351  				VSRName:                 "coffee",
  5352  				VSRNamespace:            "default",
  5353  			},
  5354  			{
  5355  				Path:                     "/internal_location_splits_3_split_1",
  5356  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  5357  				ProxyNextUpstream:        "error timeout",
  5358  				ProxyNextUpstreamTimeout: "0s",
  5359  				ProxyNextUpstreamTries:   0,
  5360  				Internal:                 true,
  5361  				ErrorPages: []version2.ErrorPage{
  5362  					{
  5363  						Name:         "@error_page_0_0",
  5364  						Codes:        "400 500",
  5365  						ResponseCode: 200,
  5366  					},
  5367  					{
  5368  						Name:         "http://nginx.com",
  5369  						Codes:        "500 502",
  5370  						ResponseCode: 301,
  5371  					},
  5372  				},
  5373  				ProxyInterceptErrors:    true,
  5374  				ProxySSLName:            "coffee-v1.default.svc",
  5375  				ProxyPassRequestHeaders: true,
  5376  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5377  				ServiceName:             "coffee-v1",
  5378  				IsVSR:                   true,
  5379  				VSRName:                 "coffee",
  5380  				VSRNamespace:            "default",
  5381  			},
  5382  			{
  5383  				Path:                     "/internal_location_splits_4_split_0",
  5384  				ProxyPass:                "http://vs_default_cafe_coffee-v1$request_uri",
  5385  				ProxyNextUpstream:        "error timeout",
  5386  				ProxyNextUpstreamTimeout: "0s",
  5387  				ProxyNextUpstreamTries:   0,
  5388  				Internal:                 true,
  5389  				ErrorPages: []version2.ErrorPage{
  5390  					{
  5391  						Name:         "@error_page_0_0",
  5392  						Codes:        "400 500",
  5393  						ResponseCode: 200,
  5394  					},
  5395  					{
  5396  						Name:         "http://nginx.com",
  5397  						Codes:        "500 502",
  5398  						ResponseCode: 301,
  5399  					},
  5400  				},
  5401  				ProxyInterceptErrors:    true,
  5402  				ProxySSLName:            "coffee-v1.default.svc",
  5403  				ProxyPassRequestHeaders: true,
  5404  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5405  				ServiceName:             "coffee-v1",
  5406  				IsVSR:                   true,
  5407  				VSRName:                 "coffee",
  5408  				VSRNamespace:            "default",
  5409  			},
  5410  			{
  5411  				Path:                     "/internal_location_splits_4_split_1",
  5412  				ProxyPass:                "http://vs_default_cafe_coffee-v2$request_uri",
  5413  				ProxyNextUpstream:        "error timeout",
  5414  				ProxyNextUpstreamTimeout: "0s",
  5415  				ProxyNextUpstreamTries:   0,
  5416  				Internal:                 true,
  5417  				ErrorPages: []version2.ErrorPage{
  5418  					{
  5419  						Name:         "@error_page_0_0",
  5420  						Codes:        "400 500",
  5421  						ResponseCode: 200,
  5422  					},
  5423  					{
  5424  						Name:         "http://nginx.com",
  5425  						Codes:        "500 502",
  5426  						ResponseCode: 301,
  5427  					},
  5428  				},
  5429  				ProxyInterceptErrors:    true,
  5430  				ProxySSLName:            "coffee-v2.default.svc",
  5431  				ProxyPassRequestHeaders: true,
  5432  				ProxySetHeaders:         []version2.Header{{Name: "Host", Value: "$host"}},
  5433  				ServiceName:             "coffee-v2",
  5434  				IsVSR:                   true,
  5435  				VSRName:                 "coffee",
  5436  				VSRNamespace:            "default",
  5437  			},
  5438  		},
  5439  		InternalRedirectLocation: version2.InternalRedirectLocation{
  5440  			Path:        "/",
  5441  			Destination: "$vs_default_cafe_matches_1",
  5442  		},
  5443  		SplitClients: []version2.SplitClient{
  5444  			{
  5445  				Source:   "$request_id",
  5446  				Variable: "$vs_default_cafe_splits_2",
  5447  				Distributions: []version2.Distribution{
  5448  					{
  5449  						Weight: "30%",
  5450  						Value:  "/internal_location_splits_2_split_0",
  5451  					},
  5452  					{
  5453  						Weight: "70%",
  5454  						Value:  "/internal_location_splits_2_split_1",
  5455  					},
  5456  				},
  5457  			},
  5458  			{
  5459  				Source:   "$request_id",
  5460  				Variable: "$vs_default_cafe_splits_3",
  5461  				Distributions: []version2.Distribution{
  5462  					{
  5463  						Weight: "90%",
  5464  						Value:  "/internal_location_splits_3_split_0",
  5465  					},
  5466  					{
  5467  						Weight: "10%",
  5468  						Value:  "/internal_location_splits_3_split_1",
  5469  					},
  5470  				},
  5471  			},
  5472  			{
  5473  				Source:   "$request_id",
  5474  				Variable: "$vs_default_cafe_splits_4",
  5475  				Distributions: []version2.Distribution{
  5476  					{
  5477  						Weight: "99%",
  5478  						Value:  "/internal_location_splits_4_split_0",
  5479  					},
  5480  					{
  5481  						Weight: "1%",
  5482  						Value:  "/internal_location_splits_4_split_1",
  5483  					},
  5484  				},
  5485  			},
  5486  		},
  5487  	}
  5488  
  5489  	cfgParams := ConfigParams{}
  5490  	enableSnippets := false
  5491  	locSnippets := ""
  5492  	crUpstreams := map[string]conf_v1.Upstream{
  5493  		"vs_default_cafe_coffee-v1": {Service: "coffee-v1"},
  5494  		"vs_default_cafe_coffee-v2": {Service: "coffee-v2"},
  5495  	}
  5496  	result := generateMatchesConfig(
  5497  		route,
  5498  		upstreamNamer,
  5499  		crUpstreams,
  5500  		variableNamer,
  5501  		index,
  5502  		scIndex,
  5503  		&cfgParams,
  5504  		errorPages,
  5505  		0,
  5506  		locSnippets,
  5507  		enableSnippets,
  5508  		0,
  5509  		true,
  5510  		"coffee",
  5511  		"default",
  5512  	)
  5513  	if !reflect.DeepEqual(result, expected) {
  5514  		t.Errorf("generateMatchesConfig() returned \n%+v but expected \n%+v", result, expected)
  5515  	}
  5516  }
  5517  
  5518  func TestGenerateValueForMatchesRouteMap(t *testing.T) {
  5519  	tests := []struct {
  5520  		input              string
  5521  		expectedValue      string
  5522  		expectedIsNegative bool
  5523  	}{
  5524  		{
  5525  			input:              "default",
  5526  			expectedValue:      `\default`,
  5527  			expectedIsNegative: false,
  5528  		},
  5529  		{
  5530  			input:              "!default",
  5531  			expectedValue:      `\default`,
  5532  			expectedIsNegative: true,
  5533  		},
  5534  		{
  5535  			input:              "hostnames",
  5536  			expectedValue:      `\hostnames`,
  5537  			expectedIsNegative: false,
  5538  		},
  5539  		{
  5540  			input:              "include",
  5541  			expectedValue:      `\include`,
  5542  			expectedIsNegative: false,
  5543  		},
  5544  		{
  5545  			input:              "volatile",
  5546  			expectedValue:      `\volatile`,
  5547  			expectedIsNegative: false,
  5548  		},
  5549  		{
  5550  			input:              "abc",
  5551  			expectedValue:      `"abc"`,
  5552  			expectedIsNegative: false,
  5553  		},
  5554  		{
  5555  			input:              "!abc",
  5556  			expectedValue:      `"abc"`,
  5557  			expectedIsNegative: true,
  5558  		},
  5559  		{
  5560  			input:              "",
  5561  			expectedValue:      `""`,
  5562  			expectedIsNegative: false,
  5563  		},
  5564  		{
  5565  			input:              "!",
  5566  			expectedValue:      `""`,
  5567  			expectedIsNegative: true,
  5568  		},
  5569  	}
  5570  
  5571  	for _, test := range tests {
  5572  		resultValue, resultIsNegative := generateValueForMatchesRouteMap(test.input)
  5573  		if resultValue != test.expectedValue {
  5574  			t.Errorf("generateValueForMatchesRouteMap(%q) returned %q but expected %q as the value", test.input, resultValue, test.expectedValue)
  5575  		}
  5576  		if resultIsNegative != test.expectedIsNegative {
  5577  			t.Errorf("generateValueForMatchesRouteMap(%q) returned %v but expected %v as the isNegative", test.input, resultIsNegative, test.expectedIsNegative)
  5578  		}
  5579  	}
  5580  }
  5581  
  5582  func TestGenerateParametersForMatchesRouteMap(t *testing.T) {
  5583  	tests := []struct {
  5584  		inputMatchedValue     string
  5585  		inputSuccessfulResult string
  5586  		expected              []version2.Parameter
  5587  	}{
  5588  		{
  5589  			inputMatchedValue:     "abc",
  5590  			inputSuccessfulResult: "1",
  5591  			expected: []version2.Parameter{
  5592  				{
  5593  					Value:  `"abc"`,
  5594  					Result: "1",
  5595  				},
  5596  				{
  5597  					Value:  "default",
  5598  					Result: "0",
  5599  				},
  5600  			},
  5601  		},
  5602  		{
  5603  			inputMatchedValue:     "!abc",
  5604  			inputSuccessfulResult: "1",
  5605  			expected: []version2.Parameter{
  5606  				{
  5607  					Value:  `"abc"`,
  5608  					Result: "0",
  5609  				},
  5610  				{
  5611  					Value:  "default",
  5612  					Result: "1",
  5613  				},
  5614  			},
  5615  		},
  5616  	}
  5617  
  5618  	for _, test := range tests {
  5619  		result := generateParametersForMatchesRouteMap(test.inputMatchedValue, test.inputSuccessfulResult)
  5620  		if !reflect.DeepEqual(result, test.expected) {
  5621  			t.Errorf("generateParametersForMatchesRouteMap(%q, %q) returned %v but expected %v", test.inputMatchedValue, test.inputSuccessfulResult, result, test.expected)
  5622  		}
  5623  	}
  5624  }
  5625  
  5626  func TestGetNameForSourceForMatchesRouteMapFromCondition(t *testing.T) {
  5627  	tests := []struct {
  5628  		input    conf_v1.Condition
  5629  		expected string
  5630  	}{
  5631  		{
  5632  			input: conf_v1.Condition{
  5633  				Header: "x-version",
  5634  			},
  5635  			expected: "$http_x_version",
  5636  		},
  5637  		{
  5638  			input: conf_v1.Condition{
  5639  				Cookie: "mycookie",
  5640  			},
  5641  			expected: "$cookie_mycookie",
  5642  		},
  5643  		{
  5644  			input: conf_v1.Condition{
  5645  				Argument: "arg",
  5646  			},
  5647  			expected: "$arg_arg",
  5648  		},
  5649  		{
  5650  			input: conf_v1.Condition{
  5651  				Variable: "$request_method",
  5652  			},
  5653  			expected: "$request_method",
  5654  		},
  5655  	}
  5656  
  5657  	for _, test := range tests {
  5658  		result := getNameForSourceForMatchesRouteMapFromCondition(test.input)
  5659  		if result != test.expected {
  5660  			t.Errorf("getNameForSourceForMatchesRouteMapFromCondition() returned %q but expected %q for input %v", result, test.expected, test.input)
  5661  		}
  5662  	}
  5663  }
  5664  
  5665  func TestGenerateLBMethod(t *testing.T) {
  5666  	defaultMethod := "random two least_conn"
  5667  
  5668  	tests := []struct {
  5669  		input    string
  5670  		expected string
  5671  	}{
  5672  		{
  5673  			input:    "",
  5674  			expected: defaultMethod,
  5675  		},
  5676  		{
  5677  			input:    "round_robin",
  5678  			expected: "",
  5679  		},
  5680  		{
  5681  			input:    "random",
  5682  			expected: "random",
  5683  		},
  5684  	}
  5685  	for _, test := range tests {
  5686  		result := generateLBMethod(test.input, defaultMethod)
  5687  		if result != test.expected {
  5688  			t.Errorf("generateLBMethod() returned %q but expected %q for input '%v'", result, test.expected, test.input)
  5689  		}
  5690  	}
  5691  }
  5692  
  5693  func TestUpstreamHasKeepalive(t *testing.T) {
  5694  	noKeepalive := 0
  5695  	keepalive := 32
  5696  
  5697  	tests := []struct {
  5698  		upstream  conf_v1.Upstream
  5699  		cfgParams *ConfigParams
  5700  		expected  bool
  5701  		msg       string
  5702  	}{
  5703  		{
  5704  			conf_v1.Upstream{},
  5705  			&ConfigParams{Keepalive: keepalive},
  5706  			true,
  5707  			"upstream keepalive not set, configparam keepalive set",
  5708  		},
  5709  		{
  5710  			conf_v1.Upstream{Keepalive: &noKeepalive},
  5711  			&ConfigParams{Keepalive: keepalive},
  5712  			false,
  5713  			"upstream keepalive set to 0, configparam keepalive set",
  5714  		},
  5715  		{
  5716  			conf_v1.Upstream{Keepalive: &keepalive},
  5717  			&ConfigParams{Keepalive: noKeepalive},
  5718  			true,
  5719  			"upstream keepalive set, configparam keepalive set to 0",
  5720  		},
  5721  	}
  5722  
  5723  	for _, test := range tests {
  5724  		result := upstreamHasKeepalive(test.upstream, test.cfgParams)
  5725  		if result != test.expected {
  5726  			t.Errorf("upstreamHasKeepalive() returned %v, but expected %v for the case of %v", result, test.expected, test.msg)
  5727  		}
  5728  	}
  5729  }
  5730  
  5731  func TestNewHealthCheckWithDefaults(t *testing.T) {
  5732  	upstreamName := "test-upstream"
  5733  	baseCfgParams := &ConfigParams{
  5734  		ProxySendTimeout:    "5s",
  5735  		ProxyReadTimeout:    "5s",
  5736  		ProxyConnectTimeout: "5s",
  5737  	}
  5738  	expected := &version2.HealthCheck{
  5739  		Name:                upstreamName,
  5740  		ProxySendTimeout:    "5s",
  5741  		ProxyReadTimeout:    "5s",
  5742  		ProxyConnectTimeout: "5s",
  5743  		ProxyPass:           fmt.Sprintf("http://%v", upstreamName),
  5744  		URI:                 "/",
  5745  		Interval:            "5s",
  5746  		Jitter:              "0s",
  5747  		Fails:               1,
  5748  		Passes:              1,
  5749  		Headers:             make(map[string]string),
  5750  	}
  5751  
  5752  	result := newHealthCheckWithDefaults(conf_v1.Upstream{}, upstreamName, baseCfgParams)
  5753  
  5754  	if !reflect.DeepEqual(result, expected) {
  5755  		t.Errorf("newHealthCheckWithDefaults returned \n%v but expected \n%v", result, expected)
  5756  	}
  5757  }
  5758  
  5759  func TestGenerateHealthCheck(t *testing.T) {
  5760  	upstreamName := "test-upstream"
  5761  	tests := []struct {
  5762  		upstream     conf_v1.Upstream
  5763  		upstreamName string
  5764  		expected     *version2.HealthCheck
  5765  		msg          string
  5766  	}{
  5767  		{
  5768  
  5769  			upstream: conf_v1.Upstream{
  5770  				HealthCheck: &conf_v1.HealthCheck{
  5771  					Enable:         true,
  5772  					Path:           "/healthz",
  5773  					Interval:       "5s",
  5774  					Jitter:         "2s",
  5775  					Fails:          3,
  5776  					Passes:         2,
  5777  					Port:           8080,
  5778  					ConnectTimeout: "20s",
  5779  					SendTimeout:    "20s",
  5780  					ReadTimeout:    "20s",
  5781  					Headers: []conf_v1.Header{
  5782  						{
  5783  							Name:  "Host",
  5784  							Value: "my.service",
  5785  						},
  5786  						{
  5787  							Name:  "User-Agent",
  5788  							Value: "nginx",
  5789  						},
  5790  					},
  5791  					StatusMatch: "! 500",
  5792  				},
  5793  			},
  5794  			upstreamName: upstreamName,
  5795  			expected: &version2.HealthCheck{
  5796  				Name:                upstreamName,
  5797  				ProxyConnectTimeout: "20s",
  5798  				ProxySendTimeout:    "20s",
  5799  				ProxyReadTimeout:    "20s",
  5800  				ProxyPass:           fmt.Sprintf("http://%v", upstreamName),
  5801  				URI:                 "/healthz",
  5802  				Interval:            "5s",
  5803  				Jitter:              "2s",
  5804  				Fails:               3,
  5805  				Passes:              2,
  5806  				Port:                8080,
  5807  				Headers: map[string]string{
  5808  					"Host":       "my.service",
  5809  					"User-Agent": "nginx",
  5810  				},
  5811  				Match: fmt.Sprintf("%v_match", upstreamName),
  5812  			},
  5813  			msg: "HealthCheck with changed parameters",
  5814  		},
  5815  		{
  5816  			upstream: conf_v1.Upstream{
  5817  				HealthCheck: &conf_v1.HealthCheck{
  5818  					Enable: true,
  5819  				},
  5820  				ProxyConnectTimeout: "30s",
  5821  				ProxyReadTimeout:    "30s",
  5822  				ProxySendTimeout:    "30s",
  5823  			},
  5824  			upstreamName: upstreamName,
  5825  			expected: &version2.HealthCheck{
  5826  				Name:                upstreamName,
  5827  				ProxyConnectTimeout: "30s",
  5828  				ProxyReadTimeout:    "30s",
  5829  				ProxySendTimeout:    "30s",
  5830  				ProxyPass:           fmt.Sprintf("http://%v", upstreamName),
  5831  				URI:                 "/",
  5832  				Interval:            "5s",
  5833  				Jitter:              "0s",
  5834  				Fails:               1,
  5835  				Passes:              1,
  5836  				Headers:             make(map[string]string),
  5837  			},
  5838  			msg: "HealthCheck with default parameters from Upstream",
  5839  		},
  5840  		{
  5841  			upstream: conf_v1.Upstream{
  5842  				HealthCheck: &conf_v1.HealthCheck{
  5843  					Enable: true,
  5844  				},
  5845  			},
  5846  			upstreamName: upstreamName,
  5847  			expected: &version2.HealthCheck{
  5848  				Name:                upstreamName,
  5849  				ProxyConnectTimeout: "5s",
  5850  				ProxyReadTimeout:    "5s",
  5851  				ProxySendTimeout:    "5s",
  5852  				ProxyPass:           fmt.Sprintf("http://%v", upstreamName),
  5853  				URI:                 "/",
  5854  				Interval:            "5s",
  5855  				Jitter:              "0s",
  5856  				Fails:               1,
  5857  				Passes:              1,
  5858  				Headers:             make(map[string]string),
  5859  			},
  5860  			msg: "HealthCheck with default parameters from ConfigMap (not defined in Upstream)",
  5861  		},
  5862  		{
  5863  			upstream:     conf_v1.Upstream{},
  5864  			upstreamName: upstreamName,
  5865  			expected:     nil,
  5866  			msg:          "HealthCheck not enabled",
  5867  		},
  5868  		{
  5869  			upstream: conf_v1.Upstream{
  5870  				HealthCheck: &conf_v1.HealthCheck{
  5871  					Enable:         true,
  5872  					Interval:       "1m 5s",
  5873  					Jitter:         "2m 3s",
  5874  					ConnectTimeout: "1m 10s",
  5875  					SendTimeout:    "1m 20s",
  5876  					ReadTimeout:    "1m 30s",
  5877  				},
  5878  			},
  5879  			upstreamName: upstreamName,
  5880  			expected: &version2.HealthCheck{
  5881  				Name:                upstreamName,
  5882  				ProxyConnectTimeout: "1m10s",
  5883  				ProxySendTimeout:    "1m20s",
  5884  				ProxyReadTimeout:    "1m30s",
  5885  				ProxyPass:           fmt.Sprintf("http://%v", upstreamName),
  5886  				URI:                 "/",
  5887  				Interval:            "1m5s",
  5888  				Jitter:              "2m3s",
  5889  				Fails:               1,
  5890  				Passes:              1,
  5891  				Headers:             make(map[string]string),
  5892  			},
  5893  			msg: "HealthCheck with time parameters have correct format",
  5894  		},
  5895  	}
  5896  
  5897  	baseCfgParams := &ConfigParams{
  5898  		ProxySendTimeout:    "5s",
  5899  		ProxyReadTimeout:    "5s",
  5900  		ProxyConnectTimeout: "5s",
  5901  	}
  5902  
  5903  	for _, test := range tests {
  5904  		result := generateHealthCheck(test.upstream, test.upstreamName, baseCfgParams)
  5905  		if !reflect.DeepEqual(result, test.expected) {
  5906  			t.Errorf("generateHealthCheck returned \n%v but expected \n%v \n for case: %v", result, test.expected, test.msg)
  5907  		}
  5908  	}
  5909  }
  5910  
  5911  func TestGenerateEndpointsForUpstream(t *testing.T) {
  5912  	name := "test"
  5913  	namespace := "test-namespace"
  5914  
  5915  	tests := []struct {
  5916  		upstream             conf_v1.Upstream
  5917  		vsEx                 *VirtualServerEx
  5918  		isPlus               bool
  5919  		isResolverConfigured bool
  5920  		expected             []string
  5921  		warningsExpected     bool
  5922  		msg                  string
  5923  	}{
  5924  		{
  5925  			upstream: conf_v1.Upstream{
  5926  				Service: name,
  5927  				Port:    80,
  5928  			},
  5929  			vsEx: &VirtualServerEx{
  5930  				VirtualServer: &conf_v1.VirtualServer{
  5931  					ObjectMeta: meta_v1.ObjectMeta{
  5932  						Name:      name,
  5933  						Namespace: namespace,
  5934  					},
  5935  				},
  5936  				Endpoints: map[string][]string{
  5937  					"test-namespace/test:80": {"example.com:80"},
  5938  				},
  5939  				ExternalNameSvcs: map[string]bool{
  5940  					"test-namespace/test": true,
  5941  				},
  5942  			},
  5943  			isPlus:               true,
  5944  			isResolverConfigured: true,
  5945  			expected:             []string{"example.com:80"},
  5946  			msg:                  "ExternalName service",
  5947  		},
  5948  		{
  5949  			upstream: conf_v1.Upstream{
  5950  				Service: name,
  5951  				Port:    80,
  5952  			},
  5953  			vsEx: &VirtualServerEx{
  5954  				VirtualServer: &conf_v1.VirtualServer{
  5955  					ObjectMeta: meta_v1.ObjectMeta{
  5956  						Name:      name,
  5957  						Namespace: namespace,
  5958  					},
  5959  				},
  5960  				Endpoints: map[string][]string{
  5961  					"test-namespace/test:80": {"example.com:80"},
  5962  				},
  5963  				ExternalNameSvcs: map[string]bool{
  5964  					"test-namespace/test": true,
  5965  				},
  5966  			},
  5967  			isPlus:               true,
  5968  			isResolverConfigured: false,
  5969  			warningsExpected:     true,
  5970  			expected:             []string{},
  5971  			msg:                  "ExternalName service without resolver configured",
  5972  		},
  5973  		{
  5974  			upstream: conf_v1.Upstream{
  5975  				Service: name,
  5976  				Port:    8080,
  5977  			},
  5978  			vsEx: &VirtualServerEx{
  5979  				VirtualServer: &conf_v1.VirtualServer{
  5980  					ObjectMeta: meta_v1.ObjectMeta{
  5981  						Name:      name,
  5982  						Namespace: namespace,
  5983  					},
  5984  				},
  5985  				Endpoints: map[string][]string{
  5986  					"test-namespace/test:8080": {"192.168.10.10:8080"},
  5987  				},
  5988  			},
  5989  			isPlus:               false,
  5990  			isResolverConfigured: false,
  5991  			expected:             []string{"192.168.10.10:8080"},
  5992  			msg:                  "Service with endpoints",
  5993  		},
  5994  		{
  5995  			upstream: conf_v1.Upstream{
  5996  				Service: name,
  5997  				Port:    8080,
  5998  			},
  5999  			vsEx: &VirtualServerEx{
  6000  				VirtualServer: &conf_v1.VirtualServer{
  6001  					ObjectMeta: meta_v1.ObjectMeta{
  6002  						Name:      name,
  6003  						Namespace: namespace,
  6004  					},
  6005  				},
  6006  				Endpoints: map[string][]string{},
  6007  			},
  6008  			isPlus:               false,
  6009  			isResolverConfigured: false,
  6010  			expected:             []string{nginx502Server},
  6011  			msg:                  "Service with no endpoints",
  6012  		},
  6013  		{
  6014  			upstream: conf_v1.Upstream{
  6015  				Service: name,
  6016  				Port:    8080,
  6017  			},
  6018  			vsEx: &VirtualServerEx{
  6019  				VirtualServer: &conf_v1.VirtualServer{
  6020  					ObjectMeta: meta_v1.ObjectMeta{
  6021  						Name:      name,
  6022  						Namespace: namespace,
  6023  					},
  6024  				},
  6025  				Endpoints: map[string][]string{},
  6026  			},
  6027  			isPlus:               true,
  6028  			isResolverConfigured: false,
  6029  			expected:             nil,
  6030  			msg:                  "Service with no endpoints",
  6031  		},
  6032  		{
  6033  			upstream: conf_v1.Upstream{
  6034  				Service:     name,
  6035  				Port:        8080,
  6036  				Subselector: map[string]string{"version": "test"},
  6037  			},
  6038  			vsEx: &VirtualServerEx{
  6039  				VirtualServer: &conf_v1.VirtualServer{
  6040  					ObjectMeta: meta_v1.ObjectMeta{
  6041  						Name:      name,
  6042  						Namespace: namespace,
  6043  					},
  6044  				},
  6045  				Endpoints: map[string][]string{
  6046  					"test-namespace/test_version=test:8080": {"192.168.10.10:8080"},
  6047  				},
  6048  			},
  6049  			isPlus:               false,
  6050  			isResolverConfigured: false,
  6051  			expected:             []string{"192.168.10.10:8080"},
  6052  			msg:                  "Upstream with subselector, with a matching endpoint",
  6053  		},
  6054  		{
  6055  			upstream: conf_v1.Upstream{
  6056  				Service:     name,
  6057  				Port:        8080,
  6058  				Subselector: map[string]string{"version": "test"},
  6059  			},
  6060  			vsEx: &VirtualServerEx{
  6061  				VirtualServer: &conf_v1.VirtualServer{
  6062  					ObjectMeta: meta_v1.ObjectMeta{
  6063  						Name:      name,
  6064  						Namespace: namespace,
  6065  					},
  6066  				},
  6067  				Endpoints: map[string][]string{
  6068  					"test-namespace/test:8080": {"192.168.10.10:8080"},
  6069  				},
  6070  			},
  6071  			isPlus:               false,
  6072  			isResolverConfigured: false,
  6073  			expected:             []string{nginx502Server},
  6074  			msg:                  "Upstream with subselector, without a matching endpoint",
  6075  		},
  6076  	}
  6077  
  6078  	for _, test := range tests {
  6079  		vsc := newVirtualServerConfigurator(
  6080  			&ConfigParams{},
  6081  			test.isPlus,
  6082  			test.isResolverConfigured,
  6083  			&StaticConfigParams{},
  6084  		)
  6085  		result := vsc.generateEndpointsForUpstream(test.vsEx.VirtualServer, namespace, test.upstream, test.vsEx)
  6086  		if !reflect.DeepEqual(result, test.expected) {
  6087  			t.Errorf("generateEndpointsForUpstream(isPlus=%v, isResolverConfigured=%v) returned %v, but expected %v for case: %v",
  6088  				test.isPlus, test.isResolverConfigured, result, test.expected, test.msg)
  6089  		}
  6090  
  6091  		if len(vsc.warnings) == 0 && test.warningsExpected {
  6092  			t.Errorf(
  6093  				"generateEndpointsForUpstream(isPlus=%v, isResolverConfigured=%v) didn't return any warnings for %v but warnings expected",
  6094  				test.isPlus,
  6095  				test.isResolverConfigured,
  6096  				test.upstream,
  6097  			)
  6098  		}
  6099  
  6100  		if len(vsc.warnings) != 0 && !test.warningsExpected {
  6101  			t.Errorf("generateEndpointsForUpstream(isPlus=%v, isResolverConfigured=%v) returned warnings for %v",
  6102  				test.isPlus, test.isResolverConfigured, test.upstream)
  6103  		}
  6104  	}
  6105  }
  6106  
  6107  func TestGenerateSlowStartForPlusWithInCompatibleLBMethods(t *testing.T) {
  6108  	serviceName := "test-slowstart-with-incompatible-LBMethods"
  6109  	upstream := conf_v1.Upstream{Service: serviceName, Port: 80, SlowStart: "10s"}
  6110  	expected := ""
  6111  
  6112  	tests := []string{
  6113  		"random",
  6114  		"ip_hash",
  6115  		"hash 123",
  6116  		"random two",
  6117  		"random two least_conn",
  6118  		"random two least_time=header",
  6119  		"random two least_time=last_byte",
  6120  	}
  6121  
  6122  	for _, lbMethod := range tests {
  6123  		vsc := newVirtualServerConfigurator(&ConfigParams{}, true, false, &StaticConfigParams{})
  6124  		result := vsc.generateSlowStartForPlus(&conf_v1.VirtualServer{}, upstream, lbMethod)
  6125  
  6126  		if !reflect.DeepEqual(result, expected) {
  6127  			t.Errorf("generateSlowStartForPlus returned %v, but expected %v for lbMethod %v", result, expected, lbMethod)
  6128  		}
  6129  
  6130  		if len(vsc.warnings) == 0 {
  6131  			t.Errorf("generateSlowStartForPlus returned no warnings for %v but warnings expected", upstream)
  6132  		}
  6133  	}
  6134  }
  6135  
  6136  func TestGenerateSlowStartForPlus(t *testing.T) {
  6137  	serviceName := "test-slowstart"
  6138  
  6139  	tests := []struct {
  6140  		upstream conf_v1.Upstream
  6141  		lbMethod string
  6142  		expected string
  6143  	}{
  6144  		{
  6145  			upstream: conf_v1.Upstream{Service: serviceName, Port: 80, SlowStart: "", LBMethod: "least_conn"},
  6146  			lbMethod: "least_conn",
  6147  			expected: "",
  6148  		},
  6149  		{
  6150  			upstream: conf_v1.Upstream{Service: serviceName, Port: 80, SlowStart: "10s", LBMethod: "least_conn"},
  6151  			lbMethod: "least_conn",
  6152  			expected: "10s",
  6153  		},
  6154  	}
  6155  
  6156  	for _, test := range tests {
  6157  		vsc := newVirtualServerConfigurator(&ConfigParams{}, true, false, &StaticConfigParams{})
  6158  		result := vsc.generateSlowStartForPlus(&conf_v1.VirtualServer{}, test.upstream, test.lbMethod)
  6159  		if !reflect.DeepEqual(result, test.expected) {
  6160  			t.Errorf("generateSlowStartForPlus returned %v, but expected %v", result, test.expected)
  6161  		}
  6162  
  6163  		if len(vsc.warnings) != 0 {
  6164  			t.Errorf("generateSlowStartForPlus returned warnings for %v", test.upstream)
  6165  		}
  6166  	}
  6167  }
  6168  
  6169  func TestCreateEndpointsFromUpstream(t *testing.T) {
  6170  	ups := version2.Upstream{
  6171  		Servers: []version2.UpstreamServer{
  6172  			{
  6173  				Address: "10.0.0.20:80",
  6174  			},
  6175  			{
  6176  				Address: "10.0.0.30:80",
  6177  			},
  6178  		},
  6179  	}
  6180  
  6181  	expected := []string{
  6182  		"10.0.0.20:80",
  6183  		"10.0.0.30:80",
  6184  	}
  6185  
  6186  	endpoints := createEndpointsFromUpstream(ups)
  6187  	if !reflect.DeepEqual(endpoints, expected) {
  6188  		t.Errorf("createEndpointsFromUpstream returned %v, but expected %v", endpoints, expected)
  6189  	}
  6190  }
  6191  
  6192  func TestGenerateUpstreamWithQueue(t *testing.T) {
  6193  	serviceName := "test-queue"
  6194  
  6195  	tests := []struct {
  6196  		name     string
  6197  		upstream conf_v1.Upstream
  6198  		isPlus   bool
  6199  		expected version2.Upstream
  6200  		msg      string
  6201  	}{
  6202  		{
  6203  			name: "test-upstream-queue",
  6204  			upstream: conf_v1.Upstream{Service: serviceName, Port: 80, Queue: &conf_v1.UpstreamQueue{
  6205  				Size:    10,
  6206  				Timeout: "10s",
  6207  			}},
  6208  			isPlus: true,
  6209  			expected: version2.Upstream{
  6210  				UpstreamLabels: version2.UpstreamLabels{
  6211  					Service: "test-queue",
  6212  				},
  6213  				Name: "test-upstream-queue",
  6214  				Queue: &version2.Queue{
  6215  					Size:    10,
  6216  					Timeout: "10s",
  6217  				},
  6218  			},
  6219  			msg: "upstream queue with size and timeout",
  6220  		},
  6221  		{
  6222  			name: "test-upstream-queue-with-default-timeout",
  6223  			upstream: conf_v1.Upstream{
  6224  				Service: serviceName,
  6225  				Port:    80,
  6226  				Queue:   &conf_v1.UpstreamQueue{Size: 10, Timeout: ""},
  6227  			},
  6228  			isPlus: true,
  6229  			expected: version2.Upstream{
  6230  				UpstreamLabels: version2.UpstreamLabels{
  6231  					Service: "test-queue",
  6232  				},
  6233  				Name: "test-upstream-queue-with-default-timeout",
  6234  				Queue: &version2.Queue{
  6235  					Size:    10,
  6236  					Timeout: "60s",
  6237  				},
  6238  			},
  6239  			msg: "upstream queue with only size",
  6240  		},
  6241  		{
  6242  			name:     "test-upstream-queue-nil",
  6243  			upstream: conf_v1.Upstream{Service: serviceName, Port: 80, Queue: nil},
  6244  			isPlus:   false,
  6245  			expected: version2.Upstream{
  6246  				UpstreamLabels: version2.UpstreamLabels{
  6247  					Service: "test-queue",
  6248  				},
  6249  				Name: "test-upstream-queue-nil",
  6250  			},
  6251  			msg: "upstream queue with nil for OSS",
  6252  		},
  6253  	}
  6254  
  6255  	for _, test := range tests {
  6256  		vsc := newVirtualServerConfigurator(&ConfigParams{}, test.isPlus, false, &StaticConfigParams{})
  6257  		result := vsc.generateUpstream(nil, test.name, test.upstream, false, []string{})
  6258  		if !reflect.DeepEqual(result, test.expected) {
  6259  			t.Errorf("generateUpstream() returned %v but expected %v for the case of %v", result, test.expected, test.msg)
  6260  		}
  6261  	}
  6262  }
  6263  
  6264  func TestGenerateQueueForPlus(t *testing.T) {
  6265  	tests := []struct {
  6266  		upstreamQueue *conf_v1.UpstreamQueue
  6267  		expected      *version2.Queue
  6268  		msg           string
  6269  	}{
  6270  		{
  6271  			upstreamQueue: &conf_v1.UpstreamQueue{Size: 10, Timeout: "10s"},
  6272  			expected:      &version2.Queue{Size: 10, Timeout: "10s"},
  6273  			msg:           "upstream queue with size and timeout",
  6274  		},
  6275  		{
  6276  			upstreamQueue: nil,
  6277  			expected:      nil,
  6278  			msg:           "upstream queue with nil",
  6279  		},
  6280  		{
  6281  			upstreamQueue: &conf_v1.UpstreamQueue{Size: 10},
  6282  			expected:      &version2.Queue{Size: 10, Timeout: "60s"},
  6283  			msg:           "upstream queue with only size",
  6284  		},
  6285  	}
  6286  
  6287  	for _, test := range tests {
  6288  		result := generateQueueForPlus(test.upstreamQueue, "60s")
  6289  		if !reflect.DeepEqual(result, test.expected) {
  6290  			t.Errorf("generateQueueForPlus() returned %v but expected %v for the case of %v", result, test.expected, test.msg)
  6291  		}
  6292  	}
  6293  }
  6294  
  6295  func TestGenerateSessionCookie(t *testing.T) {
  6296  	tests := []struct {
  6297  		sc       *conf_v1.SessionCookie
  6298  		expected *version2.SessionCookie
  6299  		msg      string
  6300  	}{
  6301  		{
  6302  			sc:       &conf_v1.SessionCookie{Enable: true, Name: "test"},
  6303  			expected: &version2.SessionCookie{Enable: true, Name: "test"},
  6304  			msg:      "session cookie with name",
  6305  		},
  6306  		{
  6307  			sc:       nil,
  6308  			expected: nil,
  6309  			msg:      "session cookie with nil",
  6310  		},
  6311  		{
  6312  			sc:       &conf_v1.SessionCookie{Name: "test"},
  6313  			expected: nil,
  6314  			msg:      "session cookie not enabled",
  6315  		},
  6316  	}
  6317  	for _, test := range tests {
  6318  		result := generateSessionCookie(test.sc)
  6319  		if !reflect.DeepEqual(result, test.expected) {
  6320  			t.Errorf("generateSessionCookie() returned %v, but expected %v for the case of: %v", result, test.expected, test.msg)
  6321  		}
  6322  	}
  6323  }
  6324  
  6325  func TestGeneratePath(t *testing.T) {
  6326  	tests := []struct {
  6327  		path     string
  6328  		expected string
  6329  	}{
  6330  		{
  6331  			path:     "/",
  6332  			expected: "/",
  6333  		},
  6334  		{
  6335  			path:     "=/exact/match",
  6336  			expected: "=/exact/match",
  6337  		},
  6338  		{
  6339  			path:     `~ *\\.jpg`,
  6340  			expected: `~ "*\\.jpg"`,
  6341  		},
  6342  		{
  6343  			path:     `~* *\\.PNG`,
  6344  			expected: `~* "*\\.PNG"`,
  6345  		},
  6346  	}
  6347  
  6348  	for _, test := range tests {
  6349  		result := generatePath(test.path)
  6350  		if result != test.expected {
  6351  			t.Errorf("generatePath() returned %v, but expected %v.", result, test.expected)
  6352  		}
  6353  	}
  6354  }
  6355  
  6356  func TestGenerateErrorPageName(t *testing.T) {
  6357  	tests := []struct {
  6358  		routeIndex int
  6359  		index      int
  6360  		expected   string
  6361  	}{
  6362  		{
  6363  			0,
  6364  			0,
  6365  			"@error_page_0_0",
  6366  		},
  6367  		{
  6368  			0,
  6369  			1,
  6370  			"@error_page_0_1",
  6371  		},
  6372  		{
  6373  			1,
  6374  			0,
  6375  			"@error_page_1_0",
  6376  		},
  6377  	}
  6378  
  6379  	for _, test := range tests {
  6380  		result := generateErrorPageName(test.routeIndex, test.index)
  6381  		if result != test.expected {
  6382  			t.Errorf("generateErrorPageName(%v, %v) returned %v but expected %v", test.routeIndex, test.index, result, test.expected)
  6383  		}
  6384  	}
  6385  }
  6386  
  6387  func TestGenerateErrorPageCodes(t *testing.T) {
  6388  	tests := []struct {
  6389  		codes    []int
  6390  		expected string
  6391  	}{
  6392  		{
  6393  			codes:    []int{400},
  6394  			expected: "400",
  6395  		},
  6396  		{
  6397  			codes:    []int{404, 405, 502},
  6398  			expected: "404 405 502",
  6399  		},
  6400  	}
  6401  
  6402  	for _, test := range tests {
  6403  		result := generateErrorPageCodes(test.codes)
  6404  		if result != test.expected {
  6405  			t.Errorf("generateErrorPageCodes(%v) returned %v but expected %v", test.codes, result, test.expected)
  6406  		}
  6407  	}
  6408  }
  6409  
  6410  func TestGenerateErrorPages(t *testing.T) {
  6411  	tests := []struct {
  6412  		upstreamName string
  6413  		errorPages   []conf_v1.ErrorPage
  6414  		expected     []version2.ErrorPage
  6415  	}{
  6416  		{}, // empty errorPages
  6417  		{
  6418  			"vs_test_test",
  6419  			[]conf_v1.ErrorPage{
  6420  				{
  6421  					Codes: []int{404, 405, 500, 502},
  6422  					Return: &conf_v1.ErrorPageReturn{
  6423  						ActionReturn: conf_v1.ActionReturn{
  6424  							Code: 200,
  6425  						},
  6426  						Headers: nil,
  6427  					},
  6428  					Redirect: nil,
  6429  				},
  6430  			},
  6431  			[]version2.ErrorPage{
  6432  				{
  6433  					Name:         "@error_page_1_0",
  6434  					Codes:        "404 405 500 502",
  6435  					ResponseCode: 200,
  6436  				},
  6437  			},
  6438  		},
  6439  		{
  6440  			"vs_test_test",
  6441  			[]conf_v1.ErrorPage{
  6442  				{
  6443  					Codes:  []int{404, 405, 500, 502},
  6444  					Return: nil,
  6445  					Redirect: &conf_v1.ErrorPageRedirect{
  6446  						ActionRedirect: conf_v1.ActionRedirect{
  6447  							URL:  "http://nginx.org",
  6448  							Code: 302,
  6449  						},
  6450  					},
  6451  				},
  6452  			},
  6453  			[]version2.ErrorPage{
  6454  				{
  6455  					Name:         "http://nginx.org",
  6456  					Codes:        "404 405 500 502",
  6457  					ResponseCode: 302,
  6458  				},
  6459  			},
  6460  		},
  6461  	}
  6462  
  6463  	for i, test := range tests {
  6464  		result := generateErrorPages(i, test.errorPages)
  6465  		if !reflect.DeepEqual(result, test.expected) {
  6466  			t.Errorf("generateErrorPages(%v, %v) returned %v but expected %v", test.upstreamName, test.errorPages, result, test.expected)
  6467  		}
  6468  	}
  6469  }
  6470  
  6471  func TestGenerateErrorPageLocations(t *testing.T) {
  6472  	tests := []struct {
  6473  		upstreamName string
  6474  		errorPages   []conf_v1.ErrorPage
  6475  		expected     []version2.ErrorPageLocation
  6476  	}{
  6477  		{},
  6478  		{
  6479  			"vs_test_test",
  6480  			[]conf_v1.ErrorPage{
  6481  				{
  6482  					Codes:  []int{404, 405, 500, 502},
  6483  					Return: nil,
  6484  					Redirect: &conf_v1.ErrorPageRedirect{
  6485  						ActionRedirect: conf_v1.ActionRedirect{
  6486  							URL:  "http://nginx.org",
  6487  							Code: 302,
  6488  						},
  6489  					},
  6490  				},
  6491  			},
  6492  			nil,
  6493  		},
  6494  		{
  6495  			"vs_test_test",
  6496  			[]conf_v1.ErrorPage{
  6497  				{
  6498  					Codes: []int{404, 405, 500, 502},
  6499  					Return: &conf_v1.ErrorPageReturn{
  6500  						ActionReturn: conf_v1.ActionReturn{
  6501  							Code: 200,
  6502  							Type: "application/json",
  6503  							Body: "Hello World",
  6504  						},
  6505  						Headers: []conf_v1.Header{
  6506  							{
  6507  								Name:  "HeaderName",
  6508  								Value: "HeaderValue",
  6509  							},
  6510  						},
  6511  					},
  6512  					Redirect: nil,
  6513  				},
  6514  			},
  6515  			[]version2.ErrorPageLocation{
  6516  				{
  6517  					Name:        "@error_page_2_0",
  6518  					DefaultType: "application/json",
  6519  					Return: &version2.Return{
  6520  						Code: 0,
  6521  						Text: "Hello World",
  6522  					},
  6523  					Headers: []version2.Header{
  6524  						{
  6525  							Name:  "HeaderName",
  6526  							Value: "HeaderValue",
  6527  						},
  6528  					},
  6529  				},
  6530  			},
  6531  		},
  6532  	}
  6533  
  6534  	for i, test := range tests {
  6535  		result := generateErrorPageLocations(i, test.errorPages)
  6536  		if !reflect.DeepEqual(result, test.expected) {
  6537  			t.Errorf("generateErrorPageLocations(%v, %v) returned %v but expected %v", test.upstreamName, test.errorPages, result, test.expected)
  6538  		}
  6539  	}
  6540  }
  6541  
  6542  func TestGenerateProxySSLName(t *testing.T) {
  6543  	result := generateProxySSLName("coffee-v1", "default")
  6544  	if result != "coffee-v1.default.svc" {
  6545  		t.Errorf("generateProxySSLName(coffee-v1, default) returned %v but expected coffee-v1.default.svc", result)
  6546  	}
  6547  }
  6548  
  6549  func TestIsTLSEnabled(t *testing.T) {
  6550  	tests := []struct {
  6551  		upstream   conf_v1.Upstream
  6552  		spiffeCert bool
  6553  		expected   bool
  6554  	}{
  6555  		{
  6556  			upstream: conf_v1.Upstream{
  6557  				TLS: conf_v1.UpstreamTLS{
  6558  					Enable: false,
  6559  				},
  6560  			},
  6561  			spiffeCert: false,
  6562  			expected:   false,
  6563  		},
  6564  		{
  6565  			upstream: conf_v1.Upstream{
  6566  				TLS: conf_v1.UpstreamTLS{
  6567  					Enable: false,
  6568  				},
  6569  			},
  6570  			spiffeCert: true,
  6571  			expected:   true,
  6572  		},
  6573  		{
  6574  			upstream: conf_v1.Upstream{
  6575  				TLS: conf_v1.UpstreamTLS{
  6576  					Enable: true,
  6577  				},
  6578  			},
  6579  			spiffeCert: true,
  6580  			expected:   true,
  6581  		},
  6582  		{
  6583  			upstream: conf_v1.Upstream{
  6584  				TLS: conf_v1.UpstreamTLS{
  6585  					Enable: true,
  6586  				},
  6587  			},
  6588  			spiffeCert: false,
  6589  			expected:   true,
  6590  		},
  6591  	}
  6592  
  6593  	for _, test := range tests {
  6594  		result := isTLSEnabled(test.upstream, test.spiffeCert)
  6595  		if result != test.expected {
  6596  			t.Errorf("isTLSEnabled(%v, %v) returned %v but expected %v", test.upstream, test.spiffeCert, result, test.expected)
  6597  		}
  6598  	}
  6599  }
  6600  
  6601  func TestGenerateRewrites(t *testing.T) {
  6602  	tests := []struct {
  6603  		path         string
  6604  		proxy        *conf_v1.ActionProxy
  6605  		internal     bool
  6606  		originalPath string
  6607  		expected     []string
  6608  	}{
  6609  		{
  6610  			proxy:    nil,
  6611  			expected: nil,
  6612  		},
  6613  		{
  6614  			proxy: &conf_v1.ActionProxy{
  6615  				RewritePath: "",
  6616  			},
  6617  			expected: nil,
  6618  		},
  6619  		{
  6620  			path: "/path",
  6621  			proxy: &conf_v1.ActionProxy{
  6622  				RewritePath: "/rewrite",
  6623  			},
  6624  			expected: nil,
  6625  		},
  6626  		{
  6627  			path:     "/_internal_path",
  6628  			internal: true,
  6629  			proxy: &conf_v1.ActionProxy{
  6630  				RewritePath: "/rewrite",
  6631  			},
  6632  			originalPath: "/path",
  6633  			expected:     []string{`^ $request_uri`, `"^/path(.*)$" "/rewrite$1" break`},
  6634  		},
  6635  		{
  6636  			path:     "~/regex",
  6637  			internal: true,
  6638  			proxy: &conf_v1.ActionProxy{
  6639  				RewritePath: "/rewrite",
  6640  			},
  6641  			originalPath: "/path",
  6642  			expected:     []string{`^ $request_uri`, `"^/path(.*)$" "/rewrite$1" break`},
  6643  		},
  6644  		{
  6645  			path:     "~/regex",
  6646  			internal: false,
  6647  			proxy: &conf_v1.ActionProxy{
  6648  				RewritePath: "/rewrite",
  6649  			},
  6650  			expected: []string{`"^/regex" "/rewrite" break`},
  6651  		},
  6652  	}
  6653  
  6654  	for _, test := range tests {
  6655  		result := generateRewrites(test.path, test.proxy, test.internal, test.originalPath)
  6656  		if !reflect.DeepEqual(result, test.expected) {
  6657  			t.Errorf("generateRewrites(%v, %v, %v, %v) returned \n %v but expected \n %v",
  6658  				test.path, test.proxy, test.internal, test.originalPath, result, test.expected)
  6659  		}
  6660  	}
  6661  }
  6662  
  6663  func TestGenerateProxyPassRewrite(t *testing.T) {
  6664  	tests := []struct {
  6665  		path     string
  6666  		proxy    *conf_v1.ActionProxy
  6667  		internal bool
  6668  		expected string
  6669  	}{
  6670  		{
  6671  			expected: "",
  6672  		},
  6673  		{
  6674  			internal: true,
  6675  			proxy: &conf_v1.ActionProxy{
  6676  				RewritePath: "/rewrite",
  6677  			},
  6678  			expected: "",
  6679  		},
  6680  		{
  6681  			path: "/path",
  6682  			proxy: &conf_v1.ActionProxy{
  6683  				RewritePath: "/rewrite",
  6684  			},
  6685  			expected: "/rewrite",
  6686  		},
  6687  		{
  6688  			path: "=/path",
  6689  			proxy: &conf_v1.ActionProxy{
  6690  				RewritePath: "/rewrite",
  6691  			},
  6692  			expected: "/rewrite",
  6693  		},
  6694  		{
  6695  			path: "~/path",
  6696  			proxy: &conf_v1.ActionProxy{
  6697  				RewritePath: "/rewrite",
  6698  			},
  6699  			expected: "",
  6700  		},
  6701  	}
  6702  
  6703  	for _, test := range tests {
  6704  		result := generateProxyPassRewrite(test.path, test.proxy, test.internal)
  6705  		if result != test.expected {
  6706  			t.Errorf("generateProxyPassRewrite(%v, %v, %v) returned %v but expected %v",
  6707  				test.path, test.proxy, test.internal, result, test.expected)
  6708  		}
  6709  	}
  6710  }
  6711  
  6712  func TestGenerateProxySetHeaders(t *testing.T) {
  6713  	tests := []struct {
  6714  		proxy    *conf_v1.ActionProxy
  6715  		expected []version2.Header
  6716  		msg      string
  6717  	}{
  6718  		{
  6719  			proxy:    nil,
  6720  			expected: []version2.Header{{Name: "Host", Value: "$host"}},
  6721  			msg:      "no action proxy",
  6722  		},
  6723  		{
  6724  			proxy:    &conf_v1.ActionProxy{},
  6725  			expected: []version2.Header{{Name: "Host", Value: "$host"}},
  6726  			msg:      "empty action proxy",
  6727  		},
  6728  		{
  6729  			proxy: &conf_v1.ActionProxy{
  6730  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6731  					Set: []conf_v1.Header{
  6732  						{
  6733  							Name:  "Header-Name",
  6734  							Value: "HeaderValue",
  6735  						},
  6736  					},
  6737  				},
  6738  			},
  6739  			expected: []version2.Header{
  6740  				{
  6741  					Name:  "Header-Name",
  6742  					Value: "HeaderValue",
  6743  				},
  6744  				{
  6745  					Name:  "Host",
  6746  					Value: "$host",
  6747  				},
  6748  			},
  6749  			msg: "set headers without host",
  6750  		},
  6751  		{
  6752  			proxy: &conf_v1.ActionProxy{
  6753  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6754  					Set: []conf_v1.Header{
  6755  						{
  6756  							Name:  "Header-Name",
  6757  							Value: "HeaderValue",
  6758  						},
  6759  						{
  6760  							Name:  "Host",
  6761  							Value: "example.com",
  6762  						},
  6763  					},
  6764  				},
  6765  			},
  6766  			expected: []version2.Header{
  6767  				{
  6768  					Name:  "Header-Name",
  6769  					Value: "HeaderValue",
  6770  				},
  6771  				{
  6772  					Name:  "Host",
  6773  					Value: "example.com",
  6774  				},
  6775  			},
  6776  			msg: "set headers with host capitalized",
  6777  		},
  6778  		{
  6779  			proxy: &conf_v1.ActionProxy{
  6780  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6781  					Set: []conf_v1.Header{
  6782  						{
  6783  							Name:  "Header-Name",
  6784  							Value: "HeaderValue",
  6785  						},
  6786  						{
  6787  							Name:  "hoST",
  6788  							Value: "example.com",
  6789  						},
  6790  					},
  6791  				},
  6792  			},
  6793  			expected: []version2.Header{
  6794  				{
  6795  					Name:  "Header-Name",
  6796  					Value: "HeaderValue",
  6797  				},
  6798  				{
  6799  					Name:  "hoST",
  6800  					Value: "example.com",
  6801  				},
  6802  			},
  6803  			msg: "set headers with host in mixed case",
  6804  		},
  6805  		{
  6806  			proxy: &conf_v1.ActionProxy{
  6807  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6808  					Set: []conf_v1.Header{
  6809  						{
  6810  							Name:  "Header-Name",
  6811  							Value: "HeaderValue",
  6812  						},
  6813  						{
  6814  							Name:  "Host",
  6815  							Value: "one.example.com",
  6816  						},
  6817  						{
  6818  							Name:  "Host",
  6819  							Value: "two.example.com",
  6820  						},
  6821  					},
  6822  				},
  6823  			},
  6824  			expected: []version2.Header{
  6825  				{
  6826  					Name:  "Header-Name",
  6827  					Value: "HeaderValue",
  6828  				},
  6829  				{
  6830  					Name:  "Host",
  6831  					Value: "one.example.com",
  6832  				},
  6833  				{
  6834  					Name:  "Host",
  6835  					Value: "two.example.com",
  6836  				},
  6837  			},
  6838  			msg: "set headers with multiple hosts",
  6839  		},
  6840  	}
  6841  
  6842  	for _, test := range tests {
  6843  		result := generateProxySetHeaders(test.proxy)
  6844  		if diff := cmp.Diff(test.expected, result); diff != "" {
  6845  			t.Errorf("generateProxySetHeaders() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  6846  		}
  6847  	}
  6848  }
  6849  
  6850  func TestGenerateProxyPassRequestHeaders(t *testing.T) {
  6851  	passTrue := true
  6852  	passFalse := false
  6853  	tests := []struct {
  6854  		proxy    *conf_v1.ActionProxy
  6855  		expected bool
  6856  	}{
  6857  		{
  6858  			proxy:    nil,
  6859  			expected: true,
  6860  		},
  6861  		{
  6862  			proxy:    &conf_v1.ActionProxy{},
  6863  			expected: true,
  6864  		},
  6865  		{
  6866  			proxy: &conf_v1.ActionProxy{
  6867  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6868  					Pass: nil,
  6869  				},
  6870  			},
  6871  			expected: true,
  6872  		},
  6873  		{
  6874  			proxy: &conf_v1.ActionProxy{
  6875  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6876  					Pass: &passTrue,
  6877  				},
  6878  			},
  6879  			expected: true,
  6880  		},
  6881  		{
  6882  			proxy: &conf_v1.ActionProxy{
  6883  				RequestHeaders: &conf_v1.ProxyRequestHeaders{
  6884  					Pass: &passFalse,
  6885  				},
  6886  			},
  6887  			expected: false,
  6888  		},
  6889  	}
  6890  
  6891  	for _, test := range tests {
  6892  		result := generateProxyPassRequestHeaders(test.proxy)
  6893  		if result != test.expected {
  6894  			t.Errorf("generateProxyPassRequestHeaders(%v) returned %v but expected %v", test.proxy, result, test.expected)
  6895  		}
  6896  	}
  6897  }
  6898  
  6899  func TestGenerateProxyHideHeaders(t *testing.T) {
  6900  	tests := []struct {
  6901  		proxy    *conf_v1.ActionProxy
  6902  		expected []string
  6903  	}{
  6904  		{
  6905  			proxy:    nil,
  6906  			expected: nil,
  6907  		},
  6908  		{
  6909  			proxy: &conf_v1.ActionProxy{
  6910  				ResponseHeaders: nil,
  6911  			},
  6912  		},
  6913  		{
  6914  			proxy: &conf_v1.ActionProxy{
  6915  				ResponseHeaders: &conf_v1.ProxyResponseHeaders{
  6916  					Hide: []string{"Header", "Header-2"},
  6917  				},
  6918  			},
  6919  			expected: []string{"Header", "Header-2"},
  6920  		},
  6921  	}
  6922  
  6923  	for _, test := range tests {
  6924  		result := generateProxyHideHeaders(test.proxy)
  6925  		if !reflect.DeepEqual(result, test.expected) {
  6926  			t.Errorf("generateProxyHideHeaders(%v) returned %v but expected %v", test.proxy, result, test.expected)
  6927  		}
  6928  	}
  6929  }
  6930  
  6931  func TestGenerateProxyPassHeaders(t *testing.T) {
  6932  	tests := []struct {
  6933  		proxy    *conf_v1.ActionProxy
  6934  		expected []string
  6935  	}{
  6936  		{
  6937  			proxy:    nil,
  6938  			expected: nil,
  6939  		},
  6940  		{
  6941  			proxy: &conf_v1.ActionProxy{
  6942  				ResponseHeaders: nil,
  6943  			},
  6944  		},
  6945  		{
  6946  			proxy: &conf_v1.ActionProxy{
  6947  				ResponseHeaders: &conf_v1.ProxyResponseHeaders{
  6948  					Pass: []string{"Header", "Header-2"},
  6949  				},
  6950  			},
  6951  			expected: []string{"Header", "Header-2"},
  6952  		},
  6953  	}
  6954  
  6955  	for _, test := range tests {
  6956  		result := generateProxyPassHeaders(test.proxy)
  6957  		if !reflect.DeepEqual(result, test.expected) {
  6958  			t.Errorf("generateProxyPassHeaders(%v) returned %v but expected %v", test.proxy, result, test.expected)
  6959  		}
  6960  	}
  6961  }
  6962  
  6963  func TestGenerateProxyIgnoreHeaders(t *testing.T) {
  6964  	tests := []struct {
  6965  		proxy    *conf_v1.ActionProxy
  6966  		expected string
  6967  	}{
  6968  		{
  6969  			proxy:    nil,
  6970  			expected: "",
  6971  		},
  6972  		{
  6973  			proxy: &conf_v1.ActionProxy{
  6974  				ResponseHeaders: nil,
  6975  			},
  6976  			expected: "",
  6977  		},
  6978  		{
  6979  			proxy: &conf_v1.ActionProxy{
  6980  				ResponseHeaders: &conf_v1.ProxyResponseHeaders{
  6981  					Ignore: []string{"Header", "Header-2"},
  6982  				},
  6983  			},
  6984  			expected: "Header Header-2",
  6985  		},
  6986  	}
  6987  
  6988  	for _, test := range tests {
  6989  		result := generateProxyIgnoreHeaders(test.proxy)
  6990  		if result != test.expected {
  6991  			t.Errorf("generateProxyIgnoreHeaders(%v) returned %v but expected %v", test.proxy, result, test.expected)
  6992  		}
  6993  	}
  6994  }
  6995  
  6996  func TestGenerateProxyAddHeaders(t *testing.T) {
  6997  	tests := []struct {
  6998  		proxy    *conf_v1.ActionProxy
  6999  		expected []version2.AddHeader
  7000  	}{
  7001  		{
  7002  			proxy:    nil,
  7003  			expected: nil,
  7004  		},
  7005  		{
  7006  			proxy:    &conf_v1.ActionProxy{},
  7007  			expected: nil,
  7008  		},
  7009  		{
  7010  			proxy: &conf_v1.ActionProxy{
  7011  				ResponseHeaders: &conf_v1.ProxyResponseHeaders{
  7012  					Add: []conf_v1.AddHeader{
  7013  						{
  7014  							Header: conf_v1.Header{
  7015  								Name:  "Header-Name",
  7016  								Value: "HeaderValue",
  7017  							},
  7018  							Always: true,
  7019  						},
  7020  						{
  7021  							Header: conf_v1.Header{
  7022  								Name:  "Server",
  7023  								Value: "myServer",
  7024  							},
  7025  							Always: false,
  7026  						},
  7027  					},
  7028  				},
  7029  			},
  7030  			expected: []version2.AddHeader{
  7031  				{
  7032  					Header: version2.Header{
  7033  						Name:  "Header-Name",
  7034  						Value: "HeaderValue",
  7035  					},
  7036  					Always: true,
  7037  				},
  7038  				{
  7039  					Header: version2.Header{
  7040  						Name:  "Server",
  7041  						Value: "myServer",
  7042  					},
  7043  					Always: false,
  7044  				},
  7045  			},
  7046  		},
  7047  	}
  7048  
  7049  	for _, test := range tests {
  7050  		result := generateProxyAddHeaders(test.proxy)
  7051  		if !reflect.DeepEqual(result, test.expected) {
  7052  			t.Errorf("generateProxyAddHeaders(%v) returned %v but expected %v", test.proxy, result, test.expected)
  7053  		}
  7054  	}
  7055  }
  7056  
  7057  func TestGetUpstreamResourceLabels(t *testing.T) {
  7058  	tests := []struct {
  7059  		owner    runtime.Object
  7060  		expected version2.UpstreamLabels
  7061  	}{
  7062  		{
  7063  			owner:    nil,
  7064  			expected: version2.UpstreamLabels{},
  7065  		},
  7066  		{
  7067  			owner: &conf_v1.VirtualServer{
  7068  				ObjectMeta: meta_v1.ObjectMeta{
  7069  					Namespace: "namespace",
  7070  					Name:      "name",
  7071  				},
  7072  			},
  7073  			expected: version2.UpstreamLabels{
  7074  				ResourceNamespace: "namespace",
  7075  				ResourceName:      "name",
  7076  				ResourceType:      "virtualserver",
  7077  			},
  7078  		},
  7079  		{
  7080  			owner: &conf_v1.VirtualServerRoute{
  7081  				ObjectMeta: meta_v1.ObjectMeta{
  7082  					Namespace: "namespace",
  7083  					Name:      "name",
  7084  				},
  7085  			},
  7086  			expected: version2.UpstreamLabels{
  7087  				ResourceNamespace: "namespace",
  7088  				ResourceName:      "name",
  7089  				ResourceType:      "virtualserverroute",
  7090  			},
  7091  		},
  7092  	}
  7093  	for _, test := range tests {
  7094  		result := getUpstreamResourceLabels(test.owner)
  7095  		if !reflect.DeepEqual(result, test.expected) {
  7096  			t.Errorf("getUpstreamResourceLabels(%+v) returned %+v but expected %+v", test.owner, result, test.expected)
  7097  		}
  7098  	}
  7099  }
  7100  
  7101  func TestAddWafConfig(t *testing.T) {
  7102  	tests := []struct {
  7103  		wafInput     *conf_v1.WAF
  7104  		polKey       string
  7105  		polNamespace string
  7106  		apResources  map[string]string
  7107  		wafConfig    *version2.WAF
  7108  		expected     *validationResults
  7109  		msg          string
  7110  	}{
  7111  		{
  7112  
  7113  			wafInput: &conf_v1.WAF{
  7114  				Enable: true,
  7115  			},
  7116  			polKey:       "default/waf-policy",
  7117  			polNamespace: "default",
  7118  			apResources:  map[string]string{},
  7119  			wafConfig: &version2.WAF{
  7120  				Enable: "on",
  7121  			},
  7122  			expected: &validationResults{isError: false},
  7123  			msg:      "valid waf config, default App Protect config",
  7124  		},
  7125  		{
  7126  
  7127  			wafInput: &conf_v1.WAF{
  7128  				Enable:   true,
  7129  				ApPolicy: "dataguard-alarm",
  7130  				SecurityLog: &conf_v1.SecurityLog{
  7131  					Enable:    true,
  7132  					ApLogConf: "logconf",
  7133  					LogDest:   "syslog:server=127.0.0.1:514",
  7134  				},
  7135  			},
  7136  			polKey:       "default/waf-policy",
  7137  			polNamespace: "default",
  7138  			apResources: map[string]string{
  7139  				"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  7140  				"default/logconf":         "/etc/nginx/waf/nac-logconfs/default-logconf",
  7141  			},
  7142  			wafConfig: &version2.WAF{
  7143  				ApPolicy:            "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  7144  				ApSecurityLogEnable: true,
  7145  				ApLogConf:           "/etc/nginx/waf/nac-logconfs/default-logconf",
  7146  			},
  7147  			expected: &validationResults{isError: false},
  7148  			msg:      "valid waf config",
  7149  		},
  7150  		{
  7151  
  7152  			wafInput: &conf_v1.WAF{
  7153  				Enable:   true,
  7154  				ApPolicy: "default/dataguard-alarm",
  7155  				SecurityLog: &conf_v1.SecurityLog{
  7156  					Enable:    true,
  7157  					ApLogConf: "default/logconf",
  7158  					LogDest:   "syslog:server=127.0.0.1:514",
  7159  				},
  7160  			},
  7161  			polKey:       "default/waf-policy",
  7162  			polNamespace: "",
  7163  			apResources: map[string]string{
  7164  				"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  7165  			},
  7166  			wafConfig: &version2.WAF{
  7167  				ApPolicy:            "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  7168  				ApSecurityLogEnable: true,
  7169  				ApLogConf:           "/etc/nginx/waf/nac-logconfs/default-logconf",
  7170  			},
  7171  			expected: &validationResults{
  7172  				isError: true,
  7173  				warnings: []string{
  7174  					`WAF policy default/waf-policy references an invalid or non-existing log config default/logconf`,
  7175  				},
  7176  			},
  7177  			msg: "invalid waf config, apLogConf references non-existing log conf",
  7178  		},
  7179  		{
  7180  
  7181  			wafInput: &conf_v1.WAF{
  7182  				Enable:   true,
  7183  				ApPolicy: "default/dataguard-alarm",
  7184  				SecurityLog: &conf_v1.SecurityLog{
  7185  					Enable:  true,
  7186  					LogDest: "syslog:server=127.0.0.1:514",
  7187  				},
  7188  			},
  7189  			polKey:       "default/waf-policy",
  7190  			polNamespace: "",
  7191  			apResources: map[string]string{
  7192  				"default/logconf": "/etc/nginx/waf/nac-logconfs/default-logconf",
  7193  			},
  7194  			wafConfig: &version2.WAF{
  7195  				ApPolicy:            "/etc/nginx/waf/nac-policies/default-dataguard-alarm",
  7196  				ApSecurityLogEnable: true,
  7197  				ApLogConf:           "/etc/nginx/waf/nac-logconfs/default-logconf",
  7198  			},
  7199  			expected: &validationResults{
  7200  				isError: true,
  7201  				warnings: []string{
  7202  					`WAF policy default/waf-policy references an invalid or non-existing App Protect policy default/dataguard-alarm`,
  7203  				},
  7204  			},
  7205  			msg: "invalid waf config, apLogConf references non-existing ap conf",
  7206  		},
  7207  		{
  7208  
  7209  			wafInput: &conf_v1.WAF{
  7210  				Enable:   true,
  7211  				ApPolicy: "ns1/dataguard-alarm",
  7212  				SecurityLog: &conf_v1.SecurityLog{
  7213  					Enable:    true,
  7214  					ApLogConf: "ns2/logconf",
  7215  					LogDest:   "syslog:server=127.0.0.1:514",
  7216  				},
  7217  			},
  7218  			polKey:       "default/waf-policy",
  7219  			polNamespace: "",
  7220  			apResources: map[string]string{
  7221  				"ns1/dataguard-alarm": "/etc/nginx/waf/nac-policies/ns1-dataguard-alarm",
  7222  				"ns2/logconf":         "/etc/nginx/waf/nac-logconfs/ns2-logconf",
  7223  			},
  7224  			wafConfig: &version2.WAF{
  7225  				ApPolicy:            "/etc/nginx/waf/nac-policies/ns1-dataguard-alarm",
  7226  				ApSecurityLogEnable: true,
  7227  				ApLogConf:           "/etc/nginx/waf/nac-logconfs/ns2-logconf",
  7228  			},
  7229  			expected: &validationResults{},
  7230  			msg:      "valid waf config, cross ns reference",
  7231  		},
  7232  		{
  7233  
  7234  			wafInput: &conf_v1.WAF{
  7235  				Enable:   false,
  7236  				ApPolicy: "dataguard-alarm",
  7237  			},
  7238  			polKey:       "default/waf-policy",
  7239  			polNamespace: "default",
  7240  			apResources: map[string]string{
  7241  				"default/dataguard-alarm": "/etc/nginx/waf/nac-policies/ns1-dataguard-alarm",
  7242  				"default/logconf":         "/etc/nginx/waf/nac-logconfs/ns2-logconf",
  7243  			},
  7244  			wafConfig: &version2.WAF{
  7245  				Enable:   "off",
  7246  				ApPolicy: "/etc/nginx/waf/nac-policies/ns1-dataguard-alarm",
  7247  			},
  7248  			expected: &validationResults{},
  7249  			msg:      "valid waf config, disable waf",
  7250  		},
  7251  	}
  7252  
  7253  	for _, test := range tests {
  7254  		polCfg := newPoliciesConfig()
  7255  		result := polCfg.addWAFConfig(test.wafInput, test.polKey, test.polNamespace, test.apResources)
  7256  		if diff := cmp.Diff(test.expected.warnings, result.warnings); diff != "" {
  7257  			t.Errorf("policiesCfg.addWAFConfig() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  7258  		}
  7259  	}
  7260  }
  7261  
  7262  func TestGenerateTime(t *testing.T) {
  7263  	tests := []struct {
  7264  		value, expected string
  7265  	}{
  7266  		{
  7267  			value:    "0s",
  7268  			expected: "0s",
  7269  		},
  7270  		{
  7271  			value:    "0",
  7272  			expected: "0s",
  7273  		},
  7274  		{
  7275  			value:    "1h",
  7276  			expected: "1h",
  7277  		},
  7278  		{
  7279  			value:    "1h 30m",
  7280  			expected: "1h30m",
  7281  		},
  7282  	}
  7283  
  7284  	for _, test := range tests {
  7285  		result := generateTime(test.value)
  7286  		if result != test.expected {
  7287  			t.Errorf("generateTime(%q) returned %q but expected %q", test.value, result, test.expected)
  7288  		}
  7289  	}
  7290  }
  7291  
  7292  func TestGenerateTimeWithDefault(t *testing.T) {
  7293  	tests := []struct {
  7294  		value, defaultValue, expected string
  7295  	}{
  7296  		{
  7297  			value:        "1h 30m",
  7298  			defaultValue: "",
  7299  			expected:     "1h30m",
  7300  		},
  7301  		{
  7302  			value:        "",
  7303  			defaultValue: "60s",
  7304  			expected:     "60s",
  7305  		},
  7306  		{
  7307  			value:        "",
  7308  			defaultValue: "test",
  7309  			expected:     "test",
  7310  		},
  7311  	}
  7312  
  7313  	for _, test := range tests {
  7314  		result := generateTimeWithDefault(test.value, test.defaultValue)
  7315  		if result != test.expected {
  7316  			t.Errorf("generateTimeWithDefault(%q, %q) returned %q but expected %q", test.value, test.defaultValue, result, test.expected)
  7317  		}
  7318  	}
  7319  }