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

     1  package k8s
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/nginxinc/kubernetes-ingress/internal/configs"
    13  	"github.com/nginxinc/kubernetes-ingress/internal/configs/version1"
    14  	"github.com/nginxinc/kubernetes-ingress/internal/configs/version2"
    15  	"github.com/nginxinc/kubernetes-ingress/internal/k8s/appprotect"
    16  	"github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets"
    17  	"github.com/nginxinc/kubernetes-ingress/internal/metrics/collectors"
    18  	"github.com/nginxinc/kubernetes-ingress/internal/nginx"
    19  	conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
    20  	conf_v1alpha1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1"
    21  	api_v1 "k8s.io/api/core/v1"
    22  	v1 "k8s.io/api/core/v1"
    23  	networking "k8s.io/api/networking/v1beta1"
    24  	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    26  	"k8s.io/apimachinery/pkg/util/intstr"
    27  	"k8s.io/client-go/kubernetes/fake"
    28  
    29  	"k8s.io/client-go/tools/cache"
    30  )
    31  
    32  func TestHasCorrectIngressClass(t *testing.T) {
    33  	ingressClass := "ing-ctrl"
    34  	incorrectIngressClass := "gce"
    35  	emptyClass := ""
    36  
    37  	testsWithoutIngressClassOnly := []struct {
    38  		lbc      *LoadBalancerController
    39  		ing      *networking.Ingress
    40  		expected bool
    41  	}{
    42  		{
    43  			&LoadBalancerController{
    44  				ingressClass:        ingressClass,
    45  				useIngressClassOnly: false,
    46  				metricsCollector:    collectors.NewControllerFakeCollector(),
    47  			},
    48  			&networking.Ingress{
    49  				ObjectMeta: meta_v1.ObjectMeta{
    50  					Annotations: map[string]string{ingressClassKey: emptyClass},
    51  				},
    52  			},
    53  			true,
    54  		},
    55  		{
    56  			&LoadBalancerController{
    57  				ingressClass:        ingressClass,
    58  				useIngressClassOnly: false,
    59  				metricsCollector:    collectors.NewControllerFakeCollector(),
    60  			},
    61  			&networking.Ingress{
    62  				ObjectMeta: meta_v1.ObjectMeta{
    63  					Annotations: map[string]string{ingressClassKey: incorrectIngressClass},
    64  				},
    65  			},
    66  			false,
    67  		},
    68  		{
    69  			&LoadBalancerController{
    70  				ingressClass:        ingressClass,
    71  				useIngressClassOnly: false,
    72  				metricsCollector:    collectors.NewControllerFakeCollector(),
    73  			},
    74  			&networking.Ingress{
    75  				ObjectMeta: meta_v1.ObjectMeta{
    76  					Annotations: map[string]string{ingressClassKey: ingressClass},
    77  				},
    78  			},
    79  			true,
    80  		},
    81  		{
    82  			&LoadBalancerController{
    83  				ingressClass:        ingressClass,
    84  				useIngressClassOnly: false,
    85  				metricsCollector:    collectors.NewControllerFakeCollector(),
    86  			},
    87  			&networking.Ingress{
    88  				ObjectMeta: meta_v1.ObjectMeta{
    89  					Annotations: map[string]string{},
    90  				},
    91  			},
    92  			true,
    93  		},
    94  	}
    95  
    96  	testsWithIngressClassOnly := []struct {
    97  		lbc      *LoadBalancerController
    98  		ing      *networking.Ingress
    99  		expected bool
   100  	}{
   101  		{
   102  			&LoadBalancerController{
   103  				ingressClass:        ingressClass,
   104  				useIngressClassOnly: true,
   105  				metricsCollector:    collectors.NewControllerFakeCollector(),
   106  			},
   107  			&networking.Ingress{
   108  				ObjectMeta: meta_v1.ObjectMeta{
   109  					Annotations: map[string]string{ingressClassKey: emptyClass},
   110  				},
   111  			},
   112  			false,
   113  		},
   114  		{
   115  			&LoadBalancerController{
   116  				ingressClass:        ingressClass,
   117  				useIngressClassOnly: true,
   118  				metricsCollector:    collectors.NewControllerFakeCollector(),
   119  			},
   120  			&networking.Ingress{
   121  				ObjectMeta: meta_v1.ObjectMeta{
   122  					Annotations: map[string]string{ingressClassKey: incorrectIngressClass},
   123  				},
   124  			},
   125  			false,
   126  		},
   127  		{
   128  			&LoadBalancerController{
   129  				ingressClass:        ingressClass,
   130  				useIngressClassOnly: true,
   131  				metricsCollector:    collectors.NewControllerFakeCollector(),
   132  			},
   133  			&networking.Ingress{
   134  				ObjectMeta: meta_v1.ObjectMeta{
   135  					Annotations: map[string]string{ingressClassKey: ingressClass},
   136  				},
   137  			},
   138  			true,
   139  		},
   140  		{
   141  			&LoadBalancerController{
   142  				ingressClass:        ingressClass,
   143  				useIngressClassOnly: true,
   144  				metricsCollector:    collectors.NewControllerFakeCollector(),
   145  			},
   146  			&networking.Ingress{
   147  				ObjectMeta: meta_v1.ObjectMeta{
   148  					Annotations: map[string]string{},
   149  				},
   150  			},
   151  			false,
   152  		},
   153  		{
   154  			&LoadBalancerController{
   155  				ingressClass:        ingressClass,
   156  				useIngressClassOnly: true, // always true for k8s >= 1.18
   157  				metricsCollector:    collectors.NewControllerFakeCollector(),
   158  			},
   159  			&networking.Ingress{
   160  				Spec: networking.IngressSpec{
   161  					IngressClassName: &incorrectIngressClass,
   162  				},
   163  			},
   164  			false,
   165  		},
   166  		{
   167  			&LoadBalancerController{
   168  				ingressClass:        ingressClass,
   169  				useIngressClassOnly: true, // always true for k8s >= 1.18
   170  				metricsCollector:    collectors.NewControllerFakeCollector(),
   171  			},
   172  			&networking.Ingress{
   173  				Spec: networking.IngressSpec{
   174  					IngressClassName: &emptyClass,
   175  				},
   176  			},
   177  			false,
   178  		},
   179  		{
   180  			&LoadBalancerController{
   181  				ingressClass:        ingressClass,
   182  				useIngressClassOnly: true, // always true for k8s >= 1.18
   183  				metricsCollector:    collectors.NewControllerFakeCollector(),
   184  			},
   185  			&networking.Ingress{
   186  				ObjectMeta: meta_v1.ObjectMeta{
   187  					Annotations: map[string]string{ingressClassKey: incorrectIngressClass},
   188  				},
   189  				Spec: networking.IngressSpec{
   190  					IngressClassName: &ingressClass,
   191  				},
   192  			},
   193  			false,
   194  		},
   195  		{
   196  			&LoadBalancerController{
   197  				ingressClass:        ingressClass,
   198  				useIngressClassOnly: true, // always true for k8s >= 1.18
   199  				metricsCollector:    collectors.NewControllerFakeCollector(),
   200  			},
   201  			&networking.Ingress{
   202  				Spec: networking.IngressSpec{
   203  					IngressClassName: &ingressClass,
   204  				},
   205  			},
   206  			true,
   207  		},
   208  	}
   209  
   210  	for _, test := range testsWithoutIngressClassOnly {
   211  		if result := test.lbc.HasCorrectIngressClass(test.ing); result != test.expected {
   212  			classAnnotation := "N/A"
   213  			if class, exists := test.ing.Annotations[ingressClassKey]; exists {
   214  				classAnnotation = class
   215  			}
   216  			t.Errorf("lbc.HasCorrectIngressClass(ing), lbc.ingressClass=%v, lbc.useIngressClassOnly=%v, ing.Annotations['%v']=%v; got %v, expected %v",
   217  				test.lbc.ingressClass, test.lbc.useIngressClassOnly, ingressClassKey, classAnnotation, result, test.expected)
   218  		}
   219  	}
   220  
   221  	for _, test := range testsWithIngressClassOnly {
   222  		if result := test.lbc.HasCorrectIngressClass(test.ing); result != test.expected {
   223  			classAnnotation := "N/A"
   224  			if class, exists := test.ing.Annotations[ingressClassKey]; exists {
   225  				classAnnotation = class
   226  			}
   227  			t.Errorf("lbc.HasCorrectIngressClass(ing), lbc.ingressClass=%v, lbc.useIngressClassOnly=%v, ing.Annotations['%v']=%v; got %v, expected %v",
   228  				test.lbc.ingressClass, test.lbc.useIngressClassOnly, ingressClassKey, classAnnotation, result, test.expected)
   229  		}
   230  	}
   231  }
   232  
   233  func deepCopyWithIngressClass(obj interface{}, class string) interface{} {
   234  	switch obj := obj.(type) {
   235  	case *conf_v1.VirtualServer:
   236  		objCopy := obj.DeepCopy()
   237  		objCopy.Spec.IngressClass = class
   238  		return objCopy
   239  	case *conf_v1.VirtualServerRoute:
   240  		objCopy := obj.DeepCopy()
   241  		objCopy.Spec.IngressClass = class
   242  		return objCopy
   243  	case *conf_v1alpha1.TransportServer:
   244  		objCopy := obj.DeepCopy()
   245  		objCopy.Spec.IngressClass = class
   246  		return objCopy
   247  	default:
   248  		panic(fmt.Sprintf("unknown type %T", obj))
   249  	}
   250  }
   251  
   252  func TestIngressClassForCustomResources(t *testing.T) {
   253  	ctrl := &LoadBalancerController{
   254  		ingressClass:        "nginx",
   255  		useIngressClassOnly: false,
   256  	}
   257  
   258  	ctrlWithUseICOnly := &LoadBalancerController{
   259  		ingressClass:        "nginx",
   260  		useIngressClassOnly: true,
   261  	}
   262  
   263  	tests := []struct {
   264  		lbc             *LoadBalancerController
   265  		objIngressClass string
   266  		expected        bool
   267  		msg             string
   268  	}{
   269  		{
   270  			lbc:             ctrl,
   271  			objIngressClass: "nginx",
   272  			expected:        true,
   273  			msg:             "Ingress Controller handles a resource that matches its IngressClass",
   274  		},
   275  		{
   276  			lbc:             ctrlWithUseICOnly,
   277  			objIngressClass: "nginx",
   278  			expected:        true,
   279  			msg:             "Ingress Controller with useIngressClassOnly handles a resource that matches its IngressClass",
   280  		},
   281  		{
   282  			lbc:             ctrl,
   283  			objIngressClass: "",
   284  			expected:        true,
   285  			msg:             "Ingress Controller handles a resource with an empty IngressClass",
   286  		},
   287  		{
   288  			lbc:             ctrlWithUseICOnly,
   289  			objIngressClass: "",
   290  			expected:        true,
   291  			msg:             "Ingress Controller with useIngressClassOnly handles a resource with an empty IngressClass",
   292  		},
   293  		{
   294  			lbc:             ctrl,
   295  			objIngressClass: "gce",
   296  			expected:        false,
   297  			msg:             "Ingress Controller doesn't handle a resource that doesn't match its IngressClass",
   298  		},
   299  		{
   300  			lbc:             ctrlWithUseICOnly,
   301  			objIngressClass: "gce",
   302  			expected:        false,
   303  			msg:             "Ingress Controller with useIngressClassOnly doesn't handle a resource that doesn't match its IngressClass",
   304  		},
   305  	}
   306  
   307  	resources := []interface{}{
   308  		&conf_v1.VirtualServer{},
   309  		&conf_v1.VirtualServerRoute{},
   310  		&conf_v1alpha1.TransportServer{},
   311  	}
   312  
   313  	for _, r := range resources {
   314  		for _, test := range tests {
   315  			obj := deepCopyWithIngressClass(r, test.objIngressClass)
   316  
   317  			result := test.lbc.HasCorrectIngressClass(obj)
   318  			if result != test.expected {
   319  				t.Errorf("HasCorrectIngressClass() returned %v but expected %v for the case of %q for %T", result, test.expected, test.msg, obj)
   320  			}
   321  		}
   322  	}
   323  }
   324  
   325  func TestComparePorts(t *testing.T) {
   326  	scenarios := []struct {
   327  		sp       v1.ServicePort
   328  		cp       v1.ContainerPort
   329  		expected bool
   330  	}{
   331  		{
   332  			// match TargetPort.strval and Protocol
   333  			v1.ServicePort{
   334  				TargetPort: intstr.FromString("name"),
   335  				Protocol:   v1.ProtocolTCP,
   336  			},
   337  			v1.ContainerPort{
   338  				Name:          "name",
   339  				Protocol:      v1.ProtocolTCP,
   340  				ContainerPort: 80,
   341  			},
   342  			true,
   343  		},
   344  		{
   345  			// don't match Name and Protocol
   346  			v1.ServicePort{
   347  				Name:     "name",
   348  				Protocol: v1.ProtocolTCP,
   349  			},
   350  			v1.ContainerPort{
   351  				Name:          "name",
   352  				Protocol:      v1.ProtocolTCP,
   353  				ContainerPort: 80,
   354  			},
   355  			false,
   356  		},
   357  		{
   358  			// TargetPort intval mismatch, don't match by TargetPort.Name
   359  			v1.ServicePort{
   360  				Name:       "name",
   361  				TargetPort: intstr.FromInt(80),
   362  			},
   363  			v1.ContainerPort{
   364  				Name:          "name",
   365  				ContainerPort: 81,
   366  			},
   367  			false,
   368  		},
   369  		{
   370  			// match by TargetPort intval
   371  			v1.ServicePort{
   372  				TargetPort: intstr.IntOrString{
   373  					IntVal: 80,
   374  				},
   375  			},
   376  			v1.ContainerPort{
   377  				ContainerPort: 80,
   378  			},
   379  			true,
   380  		},
   381  		{
   382  			// Fall back on ServicePort.Port if TargetPort is empty
   383  			v1.ServicePort{
   384  				Name: "name",
   385  				Port: 80,
   386  			},
   387  			v1.ContainerPort{
   388  				Name:          "name",
   389  				ContainerPort: 80,
   390  			},
   391  			true,
   392  		},
   393  		{
   394  			// TargetPort intval mismatch
   395  			v1.ServicePort{
   396  				TargetPort: intstr.FromInt(80),
   397  			},
   398  			v1.ContainerPort{
   399  				ContainerPort: 81,
   400  			},
   401  			false,
   402  		},
   403  		{
   404  			// don't match empty ports
   405  			v1.ServicePort{},
   406  			v1.ContainerPort{},
   407  			false,
   408  		},
   409  	}
   410  
   411  	for _, scen := range scenarios {
   412  		if scen.expected != compareContainerPortAndServicePort(scen.cp, scen.sp) {
   413  			t.Errorf("Expected: %v, ContainerPort: %v, ServicePort: %v", scen.expected, scen.cp, scen.sp)
   414  		}
   415  	}
   416  }
   417  
   418  func TestFindProbeForPods(t *testing.T) {
   419  	pods := []*v1.Pod{
   420  		{
   421  			Spec: v1.PodSpec{
   422  				Containers: []v1.Container{
   423  					{
   424  						ReadinessProbe: &v1.Probe{
   425  							ProbeHandler: v1.ProbeHandler{
   426  								HTTPGet: &v1.HTTPGetAction{
   427  									Path: "/",
   428  									Host: "asdf.com",
   429  									Port: intstr.IntOrString{
   430  										IntVal: 80,
   431  									},
   432  								},
   433  							},
   434  							PeriodSeconds: 42,
   435  						},
   436  						Ports: []v1.ContainerPort{
   437  							{
   438  								Name:          "name",
   439  								ContainerPort: 80,
   440  								Protocol:      v1.ProtocolTCP,
   441  								HostIP:        "1.2.3.4",
   442  							},
   443  						},
   444  					},
   445  				},
   446  			},
   447  		},
   448  	}
   449  	svcPort := v1.ServicePort{
   450  		TargetPort: intstr.FromInt(80),
   451  	}
   452  	probe := findProbeForPods(pods, &svcPort)
   453  	if probe == nil || probe.PeriodSeconds != 42 {
   454  		t.Errorf("ServicePort.TargetPort as int match failed: %+v", probe)
   455  	}
   456  
   457  	svcPort = v1.ServicePort{
   458  		TargetPort: intstr.FromString("name"),
   459  		Protocol:   v1.ProtocolTCP,
   460  	}
   461  	probe = findProbeForPods(pods, &svcPort)
   462  	if probe == nil || probe.PeriodSeconds != 42 {
   463  		t.Errorf("ServicePort.TargetPort as string failed: %+v", probe)
   464  	}
   465  
   466  	svcPort = v1.ServicePort{
   467  		TargetPort: intstr.FromInt(80),
   468  		Protocol:   v1.ProtocolTCP,
   469  	}
   470  	probe = findProbeForPods(pods, &svcPort)
   471  	if probe == nil || probe.PeriodSeconds != 42 {
   472  		t.Errorf("ServicePort.TargetPort as int failed: %+v", probe)
   473  	}
   474  
   475  	svcPort = v1.ServicePort{
   476  		Port: 80,
   477  	}
   478  	probe = findProbeForPods(pods, &svcPort)
   479  	if probe == nil || probe.PeriodSeconds != 42 {
   480  		t.Errorf("ServicePort.Port should match if TargetPort is not set: %+v", probe)
   481  	}
   482  
   483  	svcPort = v1.ServicePort{
   484  		TargetPort: intstr.FromString("wrong_name"),
   485  	}
   486  	probe = findProbeForPods(pods, &svcPort)
   487  	if probe != nil {
   488  		t.Errorf("ServicePort.TargetPort should not have matched string: %+v", probe)
   489  	}
   490  
   491  	svcPort = v1.ServicePort{
   492  		TargetPort: intstr.FromInt(22),
   493  	}
   494  	probe = findProbeForPods(pods, &svcPort)
   495  	if probe != nil {
   496  		t.Errorf("ServicePort.TargetPort should not have matched int: %+v", probe)
   497  	}
   498  
   499  	svcPort = v1.ServicePort{
   500  		Port: 22,
   501  	}
   502  	probe = findProbeForPods(pods, &svcPort)
   503  	if probe != nil {
   504  		t.Errorf("ServicePort.Port mismatch: %+v", probe)
   505  	}
   506  }
   507  
   508  func TestGetServicePortForIngressPort(t *testing.T) {
   509  	fakeClient := fake.NewSimpleClientset()
   510  	cnf := configs.NewConfigurator(&nginx.LocalManager{}, &configs.StaticConfigParams{}, &configs.ConfigParams{}, &version1.TemplateExecutor{}, &version2.TemplateExecutor{}, false, false, nil, false, nil, false)
   511  	lbc := LoadBalancerController{
   512  		client:           fakeClient,
   513  		ingressClass:     "nginx",
   514  		configurator:     cnf,
   515  		metricsCollector: collectors.NewControllerFakeCollector(),
   516  	}
   517  	svc := v1.Service{
   518  		TypeMeta: meta_v1.TypeMeta{},
   519  		ObjectMeta: meta_v1.ObjectMeta{
   520  			Name:      "coffee-svc",
   521  			Namespace: "default",
   522  		},
   523  		Spec: v1.ServiceSpec{
   524  			Ports: []v1.ServicePort{
   525  				{
   526  					Name:       "foo",
   527  					Port:       80,
   528  					TargetPort: intstr.FromInt(22),
   529  				},
   530  			},
   531  		},
   532  		Status: v1.ServiceStatus{},
   533  	}
   534  	ingSvcPort := intstr.FromString("foo")
   535  	svcPort := lbc.getServicePortForIngressPort(ingSvcPort, &svc)
   536  	if svcPort == nil || svcPort.Port != 80 {
   537  		t.Errorf("TargetPort string match failed: %+v", svcPort)
   538  	}
   539  
   540  	ingSvcPort = intstr.FromInt(80)
   541  	svcPort = lbc.getServicePortForIngressPort(ingSvcPort, &svc)
   542  	if svcPort == nil || svcPort.Port != 80 {
   543  		t.Errorf("TargetPort int match failed: %+v", svcPort)
   544  	}
   545  
   546  	ingSvcPort = intstr.FromInt(22)
   547  	svcPort = lbc.getServicePortForIngressPort(ingSvcPort, &svc)
   548  	if svcPort != nil {
   549  		t.Errorf("Mismatched ints should not return port: %+v", svcPort)
   550  	}
   551  	ingSvcPort = intstr.FromString("bar")
   552  	svcPort = lbc.getServicePortForIngressPort(ingSvcPort, &svc)
   553  	if svcPort != nil {
   554  		t.Errorf("Mismatched strings should not return port: %+v", svcPort)
   555  	}
   556  }
   557  
   558  func TestFormatWarningsMessages(t *testing.T) {
   559  	warnings := []string{"Test warning", "Test warning 2"}
   560  
   561  	expected := "Test warning; Test warning 2"
   562  	result := formatWarningMessages(warnings)
   563  
   564  	if result != expected {
   565  		t.Errorf("formatWarningMessages(%v) returned %v but expected %v", warnings, result, expected)
   566  	}
   567  }
   568  
   569  func TestGetEndpointsBySubselectedPods(t *testing.T) {
   570  	boolPointer := func(b bool) *bool { return &b }
   571  	tests := []struct {
   572  		desc        string
   573  		targetPort  int32
   574  		svcEps      v1.Endpoints
   575  		expectedEps []podEndpoint
   576  	}{
   577  		{
   578  			desc:       "find one endpoint",
   579  			targetPort: 80,
   580  			expectedEps: []podEndpoint{
   581  				{
   582  					Address: "1.2.3.4:80",
   583  					MeshPodOwner: configs.MeshPodOwner{
   584  						OwnerType: "deployment",
   585  						OwnerName: "deploy-1",
   586  					},
   587  				},
   588  			},
   589  		},
   590  		{
   591  			desc:        "targetPort mismatch",
   592  			targetPort:  21,
   593  			expectedEps: nil,
   594  		},
   595  	}
   596  
   597  	pods := []*v1.Pod{
   598  		{
   599  			ObjectMeta: meta_v1.ObjectMeta{
   600  				OwnerReferences: []meta_v1.OwnerReference{
   601  					{
   602  						Kind:       "Deployment",
   603  						Name:       "deploy-1",
   604  						Controller: boolPointer(true),
   605  					},
   606  				},
   607  			},
   608  			Status: v1.PodStatus{
   609  				PodIP: "1.2.3.4",
   610  			},
   611  		},
   612  	}
   613  
   614  	svcEps := v1.Endpoints{
   615  		Subsets: []v1.EndpointSubset{
   616  			{
   617  				Addresses: []v1.EndpointAddress{
   618  					{
   619  						IP:       "1.2.3.4",
   620  						Hostname: "asdf.com",
   621  					},
   622  				},
   623  				Ports: []v1.EndpointPort{
   624  					{
   625  						Port: 80,
   626  					},
   627  				},
   628  			},
   629  		},
   630  	}
   631  
   632  	for _, test := range tests {
   633  		t.Run(test.desc, func(t *testing.T) {
   634  			gotEndps := getEndpointsBySubselectedPods(test.targetPort, pods, svcEps)
   635  			if !reflect.DeepEqual(gotEndps, test.expectedEps) {
   636  				t.Errorf("getEndpointsBySubselectedPods() = %v, want %v", gotEndps, test.expectedEps)
   637  			}
   638  		})
   639  	}
   640  }
   641  
   642  func TestGetStatusFromEventTitle(t *testing.T) {
   643  	tests := []struct {
   644  		eventTitle string
   645  		expected   string
   646  	}{
   647  		{
   648  			eventTitle: "",
   649  			expected:   "",
   650  		},
   651  		{
   652  			eventTitle: "AddedOrUpdatedWithError",
   653  			expected:   "Invalid",
   654  		},
   655  		{
   656  			eventTitle: "Rejected",
   657  			expected:   "Invalid",
   658  		},
   659  		{
   660  			eventTitle: "NoVirtualServersFound",
   661  			expected:   "Invalid",
   662  		},
   663  		{
   664  			eventTitle: "Missing Secret",
   665  			expected:   "Invalid",
   666  		},
   667  		{
   668  			eventTitle: "UpdatedWithError",
   669  			expected:   "Invalid",
   670  		},
   671  		{
   672  			eventTitle: "AddedOrUpdatedWithWarning",
   673  			expected:   "Warning",
   674  		},
   675  		{
   676  			eventTitle: "UpdatedWithWarning",
   677  			expected:   "Warning",
   678  		},
   679  		{
   680  			eventTitle: "AddedOrUpdated",
   681  			expected:   "Valid",
   682  		},
   683  		{
   684  			eventTitle: "Updated",
   685  			expected:   "Valid",
   686  		},
   687  		{
   688  			eventTitle: "New State",
   689  			expected:   "",
   690  		},
   691  	}
   692  
   693  	for _, test := range tests {
   694  		result := getStatusFromEventTitle(test.eventTitle)
   695  		if result != test.expected {
   696  			t.Errorf("getStatusFromEventTitle(%v) returned %v but expected %v", test.eventTitle, result, test.expected)
   697  		}
   698  	}
   699  }
   700  
   701  func TestGetPolicies(t *testing.T) {
   702  	validPolicy := &conf_v1.Policy{
   703  		ObjectMeta: meta_v1.ObjectMeta{
   704  			Name:      "valid-policy",
   705  			Namespace: "default",
   706  		},
   707  		Spec: conf_v1.PolicySpec{
   708  			AccessControl: &conf_v1.AccessControl{
   709  				Allow: []string{"127.0.0.1"},
   710  			},
   711  		},
   712  	}
   713  
   714  	invalidPolicy := &conf_v1.Policy{
   715  		ObjectMeta: meta_v1.ObjectMeta{
   716  			Name:      "invalid-policy",
   717  			Namespace: "default",
   718  		},
   719  		Spec: conf_v1.PolicySpec{},
   720  	}
   721  
   722  	lbc := LoadBalancerController{
   723  		isNginxPlus: true,
   724  		policyLister: &cache.FakeCustomStore{
   725  			GetByKeyFunc: func(key string) (item interface{}, exists bool, err error) {
   726  				switch key {
   727  				case "default/valid-policy":
   728  					return validPolicy, true, nil
   729  				case "default/invalid-policy":
   730  					return invalidPolicy, true, nil
   731  				case "nginx-ingress/valid-policy":
   732  					return nil, false, nil
   733  				default:
   734  					return nil, false, errors.New("GetByKey error")
   735  				}
   736  			},
   737  		},
   738  	}
   739  
   740  	policyRefs := []conf_v1.PolicyReference{
   741  		{
   742  			Name: "valid-policy",
   743  			// Namespace is implicit here
   744  		},
   745  		{
   746  			Name:      "invalid-policy",
   747  			Namespace: "default",
   748  		},
   749  		{
   750  			Name:      "valid-policy", // doesn't exist
   751  			Namespace: "nginx-ingress",
   752  		},
   753  		{
   754  			Name:      "some-policy", // will make lister return error
   755  			Namespace: "nginx-ingress",
   756  		},
   757  	}
   758  
   759  	expectedPolicies := []*conf_v1.Policy{validPolicy}
   760  	expectedErrors := []error{
   761  		errors.New("Policy default/invalid-policy is invalid: spec: Invalid value: \"\": must specify exactly one of: `accessControl`, `rateLimit`, `ingressMTLS`, `egressMTLS`, `jwt`, `oidc`, `waf`"),
   762  		errors.New("Policy nginx-ingress/valid-policy doesn't exist"),
   763  		errors.New("Failed to get policy nginx-ingress/some-policy: GetByKey error"),
   764  	}
   765  
   766  	result, errors := lbc.getPolicies(policyRefs, "default")
   767  	if !reflect.DeepEqual(result, expectedPolicies) {
   768  		t.Errorf("lbc.getPolicies() returned \n%v but \nexpected %v", result, expectedPolicies)
   769  	}
   770  	if diff := cmp.Diff(expectedErrors, errors, cmp.Comparer(errorComparer)); diff != "" {
   771  		t.Errorf("lbc.getPolicies() mismatch (-want +got):\n%s", diff)
   772  	}
   773  }
   774  
   775  func TestCreatePolicyMap(t *testing.T) {
   776  	policies := []*conf_v1.Policy{
   777  		{
   778  			ObjectMeta: meta_v1.ObjectMeta{
   779  				Name:      "policy-1",
   780  				Namespace: "default",
   781  			},
   782  		},
   783  		{
   784  			ObjectMeta: meta_v1.ObjectMeta{
   785  				Name:      "policy-2",
   786  				Namespace: "default",
   787  			},
   788  		},
   789  		{
   790  			ObjectMeta: meta_v1.ObjectMeta{
   791  				Name:      "policy-1",
   792  				Namespace: "default",
   793  			},
   794  		},
   795  		{
   796  			ObjectMeta: meta_v1.ObjectMeta{
   797  				Name:      "policy-1",
   798  				Namespace: "nginx-ingress",
   799  			},
   800  		},
   801  	}
   802  
   803  	expected := map[string]*conf_v1.Policy{
   804  		"default/policy-1": {
   805  			ObjectMeta: meta_v1.ObjectMeta{
   806  				Name:      "policy-1",
   807  				Namespace: "default",
   808  			},
   809  		},
   810  		"default/policy-2": {
   811  			ObjectMeta: meta_v1.ObjectMeta{
   812  				Name:      "policy-2",
   813  				Namespace: "default",
   814  			},
   815  		},
   816  		"nginx-ingress/policy-1": {
   817  			ObjectMeta: meta_v1.ObjectMeta{
   818  				Name:      "policy-1",
   819  				Namespace: "nginx-ingress",
   820  			},
   821  		},
   822  	}
   823  
   824  	result := createPolicyMap(policies)
   825  	if !reflect.DeepEqual(result, expected) {
   826  		t.Errorf("createPolicyMap() returned \n%s but expected \n%s", policyMapToString(result), policyMapToString(expected))
   827  	}
   828  }
   829  
   830  func TestGetPodOwnerTypeAndName(t *testing.T) {
   831  	tests := []struct {
   832  		desc    string
   833  		expType string
   834  		expName string
   835  		pod     *v1.Pod
   836  	}{
   837  		{
   838  			desc:    "deployment",
   839  			expType: "deployment",
   840  			expName: "deploy-name",
   841  			pod:     &v1.Pod{ObjectMeta: createTestObjMeta("Deployment", "deploy-name", true)},
   842  		},
   843  		{
   844  			desc:    "stateful set",
   845  			expType: "statefulset",
   846  			expName: "statefulset-name",
   847  			pod:     &v1.Pod{ObjectMeta: createTestObjMeta("StatefulSet", "statefulset-name", true)},
   848  		},
   849  		{
   850  			desc:    "daemon set",
   851  			expType: "daemonset",
   852  			expName: "daemonset-name",
   853  			pod:     &v1.Pod{ObjectMeta: createTestObjMeta("DaemonSet", "daemonset-name", true)},
   854  		},
   855  		{
   856  			desc:    "replica set with no pod hash",
   857  			expType: "deployment",
   858  			expName: "replicaset-name",
   859  			pod:     &v1.Pod{ObjectMeta: createTestObjMeta("ReplicaSet", "replicaset-name", false)},
   860  		},
   861  		{
   862  			desc:    "replica set with pod hash",
   863  			expType: "deployment",
   864  			expName: "replicaset-name",
   865  			pod: &v1.Pod{
   866  				ObjectMeta: createTestObjMeta("ReplicaSet", "replicaset-name-67c6f7c5fd", true),
   867  			},
   868  		},
   869  		{
   870  			desc:    "nil controller should use default values",
   871  			expType: "deployment",
   872  			expName: "deploy-name",
   873  			pod: &v1.Pod{
   874  				ObjectMeta: meta_v1.ObjectMeta{
   875  					OwnerReferences: []meta_v1.OwnerReference{
   876  						{
   877  							Name:       "deploy-name",
   878  							Controller: nil,
   879  						},
   880  					},
   881  				},
   882  			},
   883  		},
   884  	}
   885  
   886  	for _, test := range tests {
   887  		t.Run(test.desc, func(t *testing.T) {
   888  			actualType, actualName := getPodOwnerTypeAndName(test.pod)
   889  			if actualType != test.expType {
   890  				t.Errorf("getPodOwnerTypeAndName() returned %s for owner type but expected %s", actualType, test.expType)
   891  			}
   892  			if actualName != test.expName {
   893  				t.Errorf("getPodOwnerTypeAndName() returned %s for owner name but expected %s", actualName, test.expName)
   894  			}
   895  		})
   896  	}
   897  }
   898  
   899  func createTestObjMeta(kind, name string, podHashLabel bool) meta_v1.ObjectMeta {
   900  	controller := true
   901  	meta := meta_v1.ObjectMeta{
   902  		OwnerReferences: []meta_v1.OwnerReference{
   903  			{
   904  				Kind:       kind,
   905  				Name:       name,
   906  				Controller: &controller,
   907  			},
   908  		},
   909  	}
   910  	if podHashLabel {
   911  		meta.Labels = map[string]string{
   912  			"pod-template-hash": "67c6f7c5fd",
   913  		}
   914  	}
   915  	return meta
   916  }
   917  
   918  func policyMapToString(policies map[string]*conf_v1.Policy) string {
   919  	var keys []string
   920  	for k := range policies {
   921  		keys = append(keys, k)
   922  	}
   923  	sort.Strings(keys)
   924  
   925  	var b strings.Builder
   926  
   927  	b.WriteString("[ ")
   928  	for _, k := range keys {
   929  		fmt.Fprintf(&b, "%q: '%s/%s', ", k, policies[k].Namespace, policies[k].Name)
   930  	}
   931  	b.WriteString("]")
   932  
   933  	return b.String()
   934  }
   935  
   936  type testResource struct {
   937  	keyWithKind string
   938  }
   939  
   940  func (*testResource) GetObjectMeta() *meta_v1.ObjectMeta {
   941  	return nil
   942  }
   943  
   944  func (t *testResource) GetKeyWithKind() string {
   945  	return t.keyWithKind
   946  }
   947  
   948  func (*testResource) AcquireHost(string) {
   949  }
   950  
   951  func (*testResource) ReleaseHost(string) {
   952  }
   953  
   954  func (*testResource) Wins(Resource) bool {
   955  	return false
   956  }
   957  
   958  func (*testResource) IsSame(Resource) bool {
   959  	return false
   960  }
   961  
   962  func (*testResource) AddWarning(string) {
   963  }
   964  
   965  func (*testResource) IsEqual(Resource) bool {
   966  	return false
   967  }
   968  
   969  func (t *testResource) String() string {
   970  	return t.keyWithKind
   971  }
   972  
   973  func TestRemoveDuplicateResources(t *testing.T) {
   974  	tests := []struct {
   975  		resources []Resource
   976  		expected  []Resource
   977  	}{
   978  		{
   979  			resources: []Resource{
   980  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-1"},
   981  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-2"},
   982  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-2"},
   983  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-3"},
   984  			},
   985  			expected: []Resource{
   986  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-1"},
   987  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-2"},
   988  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-3"},
   989  			},
   990  		},
   991  		{
   992  			resources: []Resource{
   993  				&testResource{keyWithKind: "VirtualServer/ns-2/vs-3"},
   994  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-3"},
   995  			},
   996  			expected: []Resource{
   997  				&testResource{keyWithKind: "VirtualServer/ns-2/vs-3"},
   998  				&testResource{keyWithKind: "VirtualServer/ns-1/vs-3"},
   999  			},
  1000  		},
  1001  	}
  1002  
  1003  	for _, test := range tests {
  1004  		result := removeDuplicateResources(test.resources)
  1005  		if !reflect.DeepEqual(result, test.expected) {
  1006  			t.Errorf("removeDuplicateResources() returned \n%v but expected \n%v", result, test.expected)
  1007  		}
  1008  	}
  1009  }
  1010  
  1011  func TestFindPoliciesForSecret(t *testing.T) {
  1012  	jwtPol1 := &conf_v1.Policy{
  1013  		ObjectMeta: meta_v1.ObjectMeta{
  1014  			Name:      "jwt-policy",
  1015  			Namespace: "default",
  1016  		},
  1017  		Spec: conf_v1.PolicySpec{
  1018  			JWTAuth: &conf_v1.JWTAuth{
  1019  				Secret: "jwk-secret",
  1020  			},
  1021  		},
  1022  	}
  1023  
  1024  	jwtPol2 := &conf_v1.Policy{
  1025  		ObjectMeta: meta_v1.ObjectMeta{
  1026  			Name:      "jwt-policy",
  1027  			Namespace: "ns-1",
  1028  		},
  1029  		Spec: conf_v1.PolicySpec{
  1030  			JWTAuth: &conf_v1.JWTAuth{
  1031  				Secret: "jwk-secret",
  1032  			},
  1033  		},
  1034  	}
  1035  
  1036  	ingTLSPol := &conf_v1.Policy{
  1037  		ObjectMeta: meta_v1.ObjectMeta{
  1038  			Name:      "ingress-mtls-policy",
  1039  			Namespace: "default",
  1040  		},
  1041  		Spec: conf_v1.PolicySpec{
  1042  			IngressMTLS: &conf_v1.IngressMTLS{
  1043  				ClientCertSecret: "ingress-mtls-secret",
  1044  			},
  1045  		},
  1046  	}
  1047  	egTLSPol := &conf_v1.Policy{
  1048  		ObjectMeta: meta_v1.ObjectMeta{
  1049  			Name:      "egress-mtls-policy",
  1050  			Namespace: "default",
  1051  		},
  1052  		Spec: conf_v1.PolicySpec{
  1053  			EgressMTLS: &conf_v1.EgressMTLS{
  1054  				TLSSecret: "egress-mtls-secret",
  1055  			},
  1056  		},
  1057  	}
  1058  	egTLSPol2 := &conf_v1.Policy{
  1059  		ObjectMeta: meta_v1.ObjectMeta{
  1060  			Name:      "egress-trusted-policy",
  1061  			Namespace: "default",
  1062  		},
  1063  		Spec: conf_v1.PolicySpec{
  1064  			EgressMTLS: &conf_v1.EgressMTLS{
  1065  				TrustedCertSecret: "egress-trusted-secret",
  1066  			},
  1067  		},
  1068  	}
  1069  	oidcPol := &conf_v1.Policy{
  1070  		ObjectMeta: meta_v1.ObjectMeta{
  1071  			Name:      "oidc-policy",
  1072  			Namespace: "default",
  1073  		},
  1074  		Spec: conf_v1.PolicySpec{
  1075  			OIDC: &conf_v1.OIDC{
  1076  				ClientSecret: "oidc-secret",
  1077  			},
  1078  		},
  1079  	}
  1080  
  1081  	tests := []struct {
  1082  		policies        []*conf_v1.Policy
  1083  		secretNamespace string
  1084  		secretName      string
  1085  		expected        []*conf_v1.Policy
  1086  		msg             string
  1087  	}{
  1088  		{
  1089  			policies:        []*conf_v1.Policy{jwtPol1},
  1090  			secretNamespace: "default",
  1091  			secretName:      "jwk-secret",
  1092  			expected:        []*conf_v1.Policy{jwtPol1},
  1093  			msg:             "Find policy in default ns",
  1094  		},
  1095  		{
  1096  			policies:        []*conf_v1.Policy{jwtPol2},
  1097  			secretNamespace: "default",
  1098  			secretName:      "jwk-secret",
  1099  			expected:        nil,
  1100  			msg:             "Ignore policies in other namespaces",
  1101  		},
  1102  		{
  1103  			policies:        []*conf_v1.Policy{jwtPol1, jwtPol2},
  1104  			secretNamespace: "default",
  1105  			secretName:      "jwk-secret",
  1106  			expected:        []*conf_v1.Policy{jwtPol1},
  1107  			msg:             "Find policy in default ns, ignore other",
  1108  		},
  1109  		{
  1110  			policies:        []*conf_v1.Policy{ingTLSPol},
  1111  			secretNamespace: "default",
  1112  			secretName:      "ingress-mtls-secret",
  1113  			expected:        []*conf_v1.Policy{ingTLSPol},
  1114  			msg:             "Find policy in default ns",
  1115  		},
  1116  		{
  1117  			policies:        []*conf_v1.Policy{jwtPol1, ingTLSPol},
  1118  			secretNamespace: "default",
  1119  			secretName:      "ingress-mtls-secret",
  1120  			expected:        []*conf_v1.Policy{ingTLSPol},
  1121  			msg:             "Find policy in default ns, ignore other types",
  1122  		},
  1123  		{
  1124  			policies:        []*conf_v1.Policy{egTLSPol},
  1125  			secretNamespace: "default",
  1126  			secretName:      "egress-mtls-secret",
  1127  			expected:        []*conf_v1.Policy{egTLSPol},
  1128  			msg:             "Find policy in default ns",
  1129  		},
  1130  		{
  1131  			policies:        []*conf_v1.Policy{jwtPol1, egTLSPol},
  1132  			secretNamespace: "default",
  1133  			secretName:      "egress-mtls-secret",
  1134  			expected:        []*conf_v1.Policy{egTLSPol},
  1135  			msg:             "Find policy in default ns, ignore other types",
  1136  		},
  1137  		{
  1138  			policies:        []*conf_v1.Policy{egTLSPol2},
  1139  			secretNamespace: "default",
  1140  			secretName:      "egress-trusted-secret",
  1141  			expected:        []*conf_v1.Policy{egTLSPol2},
  1142  			msg:             "Find policy in default ns",
  1143  		},
  1144  		{
  1145  			policies:        []*conf_v1.Policy{egTLSPol, egTLSPol2},
  1146  			secretNamespace: "default",
  1147  			secretName:      "egress-trusted-secret",
  1148  			expected:        []*conf_v1.Policy{egTLSPol2},
  1149  			msg:             "Find policy in default ns, ignore other types",
  1150  		},
  1151  		{
  1152  			policies:        []*conf_v1.Policy{oidcPol},
  1153  			secretNamespace: "default",
  1154  			secretName:      "oidc-secret",
  1155  			expected:        []*conf_v1.Policy{oidcPol},
  1156  			msg:             "Find policy in default ns",
  1157  		},
  1158  		{
  1159  			policies:        []*conf_v1.Policy{ingTLSPol, oidcPol},
  1160  			secretNamespace: "default",
  1161  			secretName:      "oidc-secret",
  1162  			expected:        []*conf_v1.Policy{oidcPol},
  1163  			msg:             "Find policy in default ns, ignore other types",
  1164  		},
  1165  	}
  1166  	for _, test := range tests {
  1167  		result := findPoliciesForSecret(test.policies, test.secretNamespace, test.secretName)
  1168  		if diff := cmp.Diff(test.expected, result); diff != "" {
  1169  			t.Errorf("findPoliciesForSecret() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1170  		}
  1171  	}
  1172  }
  1173  
  1174  func errorComparer(e1, e2 error) bool {
  1175  	if e1 == nil || e2 == nil {
  1176  		return errors.Is(e1, e2)
  1177  	}
  1178  
  1179  	return e1.Error() == e2.Error()
  1180  }
  1181  
  1182  func TestAddJWTSecrets(t *testing.T) {
  1183  	invalidErr := errors.New("invalid")
  1184  	validJWKSecret := &v1.Secret{
  1185  		ObjectMeta: meta_v1.ObjectMeta{
  1186  			Name:      "valid-jwk-secret",
  1187  			Namespace: "default",
  1188  		},
  1189  		Type: secrets.SecretTypeJWK,
  1190  	}
  1191  	invalidJWKSecret := &v1.Secret{
  1192  		ObjectMeta: meta_v1.ObjectMeta{
  1193  			Name:      "invalid-jwk-secret",
  1194  			Namespace: "default",
  1195  		},
  1196  		Type: secrets.SecretTypeJWK,
  1197  	}
  1198  
  1199  	tests := []struct {
  1200  		policies           []*conf_v1.Policy
  1201  		expectedSecretRefs map[string]*secrets.SecretReference
  1202  		wantErr            bool
  1203  		msg                string
  1204  	}{
  1205  		{
  1206  			policies: []*conf_v1.Policy{
  1207  				{
  1208  					ObjectMeta: meta_v1.ObjectMeta{
  1209  						Name:      "jwt-policy",
  1210  						Namespace: "default",
  1211  					},
  1212  					Spec: conf_v1.PolicySpec{
  1213  						JWTAuth: &conf_v1.JWTAuth{
  1214  							Secret: "valid-jwk-secret",
  1215  							Realm:  "My API",
  1216  						},
  1217  					},
  1218  				},
  1219  			},
  1220  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1221  				"default/valid-jwk-secret": {
  1222  					Secret: validJWKSecret,
  1223  					Path:   "/etc/nginx/secrets/default-valid-jwk-secret",
  1224  				},
  1225  			},
  1226  			wantErr: false,
  1227  			msg:     "test getting valid secret",
  1228  		},
  1229  		{
  1230  			policies:           []*conf_v1.Policy{},
  1231  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1232  			wantErr:            false,
  1233  			msg:                "test getting valid secret with no policy",
  1234  		},
  1235  		{
  1236  			policies: []*conf_v1.Policy{
  1237  				{
  1238  					ObjectMeta: meta_v1.ObjectMeta{
  1239  						Name:      "jwt-policy",
  1240  						Namespace: "default",
  1241  					},
  1242  					Spec: conf_v1.PolicySpec{
  1243  						AccessControl: &conf_v1.AccessControl{
  1244  							Allow: []string{"127.0.0.1"},
  1245  						},
  1246  					},
  1247  				},
  1248  			},
  1249  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1250  			wantErr:            false,
  1251  			msg:                "test getting invalid secret with wrong policy",
  1252  		},
  1253  		{
  1254  			policies: []*conf_v1.Policy{
  1255  				{
  1256  					ObjectMeta: meta_v1.ObjectMeta{
  1257  						Name:      "jwt-policy",
  1258  						Namespace: "default",
  1259  					},
  1260  					Spec: conf_v1.PolicySpec{
  1261  						JWTAuth: &conf_v1.JWTAuth{
  1262  							Secret: "invalid-jwk-secret",
  1263  							Realm:  "My API",
  1264  						},
  1265  					},
  1266  				},
  1267  			},
  1268  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1269  				"default/invalid-jwk-secret": {
  1270  					Secret: invalidJWKSecret,
  1271  					Error:  invalidErr,
  1272  				},
  1273  			},
  1274  			wantErr: true,
  1275  			msg:     "test getting invalid secret",
  1276  		},
  1277  	}
  1278  
  1279  	lbc := LoadBalancerController{
  1280  		secretStore: secrets.NewFakeSecretsStore(map[string]*secrets.SecretReference{
  1281  			"default/valid-jwk-secret": {
  1282  				Secret: validJWKSecret,
  1283  				Path:   "/etc/nginx/secrets/default-valid-jwk-secret",
  1284  			},
  1285  			"default/invalid-jwk-secret": {
  1286  				Secret: invalidJWKSecret,
  1287  				Error:  invalidErr,
  1288  			},
  1289  		}),
  1290  	}
  1291  
  1292  	for _, test := range tests {
  1293  		result := make(map[string]*secrets.SecretReference)
  1294  
  1295  		err := lbc.addJWTSecretRefs(result, test.policies)
  1296  		if (err != nil) != test.wantErr {
  1297  			t.Errorf("addJWTSecretRefs() returned %v, for the case of %v", err, test.msg)
  1298  		}
  1299  
  1300  		if diff := cmp.Diff(test.expectedSecretRefs, result, cmp.Comparer(errorComparer)); diff != "" {
  1301  			t.Errorf("addJWTSecretRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1302  		}
  1303  	}
  1304  }
  1305  
  1306  func TestAddIngressMTLSSecret(t *testing.T) {
  1307  	invalidErr := errors.New("invalid")
  1308  	validSecret := &v1.Secret{
  1309  		ObjectMeta: meta_v1.ObjectMeta{
  1310  			Name:      "valid-ingress-mtls-secret",
  1311  			Namespace: "default",
  1312  		},
  1313  		Type: secrets.SecretTypeCA,
  1314  	}
  1315  	invalidSecret := &v1.Secret{
  1316  		ObjectMeta: meta_v1.ObjectMeta{
  1317  			Name:      "invalid-ingress-mtls-secret",
  1318  			Namespace: "default",
  1319  		},
  1320  		Type: secrets.SecretTypeCA,
  1321  	}
  1322  
  1323  	tests := []struct {
  1324  		policies           []*conf_v1.Policy
  1325  		expectedSecretRefs map[string]*secrets.SecretReference
  1326  		wantErr            bool
  1327  		msg                string
  1328  	}{
  1329  		{
  1330  			policies: []*conf_v1.Policy{
  1331  				{
  1332  					ObjectMeta: meta_v1.ObjectMeta{
  1333  						Name:      "ingress-mtls-policy",
  1334  						Namespace: "default",
  1335  					},
  1336  					Spec: conf_v1.PolicySpec{
  1337  						IngressMTLS: &conf_v1.IngressMTLS{
  1338  							ClientCertSecret: "valid-ingress-mtls-secret",
  1339  						},
  1340  					},
  1341  				},
  1342  			},
  1343  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1344  				"default/valid-ingress-mtls-secret": {
  1345  					Secret: validSecret,
  1346  					Path:   "/etc/nginx/secrets/default-valid-ingress-mtls-secret",
  1347  				},
  1348  			},
  1349  			wantErr: false,
  1350  			msg:     "test getting valid secret",
  1351  		},
  1352  		{
  1353  			policies:           []*conf_v1.Policy{},
  1354  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1355  			wantErr:            false,
  1356  			msg:                "test getting valid secret with no policy",
  1357  		},
  1358  		{
  1359  			policies: []*conf_v1.Policy{
  1360  				{
  1361  					ObjectMeta: meta_v1.ObjectMeta{
  1362  						Name:      "ingress-mtls-policy",
  1363  						Namespace: "default",
  1364  					},
  1365  					Spec: conf_v1.PolicySpec{
  1366  						AccessControl: &conf_v1.AccessControl{
  1367  							Allow: []string{"127.0.0.1"},
  1368  						},
  1369  					},
  1370  				},
  1371  			},
  1372  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1373  			wantErr:            false,
  1374  			msg:                "test getting valid secret with wrong policy",
  1375  		},
  1376  		{
  1377  			policies: []*conf_v1.Policy{
  1378  				{
  1379  					ObjectMeta: meta_v1.ObjectMeta{
  1380  						Name:      "ingress-mtls-policy",
  1381  						Namespace: "default",
  1382  					},
  1383  					Spec: conf_v1.PolicySpec{
  1384  						IngressMTLS: &conf_v1.IngressMTLS{
  1385  							ClientCertSecret: "invalid-ingress-mtls-secret",
  1386  						},
  1387  					},
  1388  				},
  1389  			},
  1390  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1391  				"default/invalid-ingress-mtls-secret": {
  1392  					Secret: invalidSecret,
  1393  					Error:  invalidErr,
  1394  				},
  1395  			},
  1396  			wantErr: true,
  1397  			msg:     "test getting invalid secret",
  1398  		},
  1399  	}
  1400  
  1401  	lbc := LoadBalancerController{
  1402  		secretStore: secrets.NewFakeSecretsStore(map[string]*secrets.SecretReference{
  1403  			"default/valid-ingress-mtls-secret": {
  1404  				Secret: validSecret,
  1405  				Path:   "/etc/nginx/secrets/default-valid-ingress-mtls-secret",
  1406  			},
  1407  			"default/invalid-ingress-mtls-secret": {
  1408  				Secret: invalidSecret,
  1409  				Error:  invalidErr,
  1410  			},
  1411  		}),
  1412  	}
  1413  
  1414  	for _, test := range tests {
  1415  		result := make(map[string]*secrets.SecretReference)
  1416  
  1417  		err := lbc.addIngressMTLSSecretRefs(result, test.policies)
  1418  		if (err != nil) != test.wantErr {
  1419  			t.Errorf("addIngressMTLSSecretRefs() returned %v, for the case of %v", err, test.msg)
  1420  		}
  1421  
  1422  		if diff := cmp.Diff(test.expectedSecretRefs, result, cmp.Comparer(errorComparer)); diff != "" {
  1423  			t.Errorf("addIngressMTLSSecretRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1424  		}
  1425  	}
  1426  }
  1427  
  1428  func TestAddEgressMTLSSecrets(t *testing.T) {
  1429  	invalidErr := errors.New("invalid")
  1430  	validMTLSSecret := &v1.Secret{
  1431  		ObjectMeta: meta_v1.ObjectMeta{
  1432  			Name:      "valid-egress-mtls-secret",
  1433  			Namespace: "default",
  1434  		},
  1435  		Type: api_v1.SecretTypeTLS,
  1436  	}
  1437  	validTrustedSecret := &v1.Secret{
  1438  		ObjectMeta: meta_v1.ObjectMeta{
  1439  			Name:      "valid-egress-trusted-secret",
  1440  			Namespace: "default",
  1441  		},
  1442  		Type: secrets.SecretTypeCA,
  1443  	}
  1444  	invalidMTLSSecret := &v1.Secret{
  1445  		ObjectMeta: meta_v1.ObjectMeta{
  1446  			Name:      "invalid-egress-mtls-secret",
  1447  			Namespace: "default",
  1448  		},
  1449  		Type: api_v1.SecretTypeTLS,
  1450  	}
  1451  	invalidTrustedSecret := &v1.Secret{
  1452  		ObjectMeta: meta_v1.ObjectMeta{
  1453  			Name:      "invalid-egress-trusted-secret",
  1454  			Namespace: "default",
  1455  		},
  1456  		Type: secrets.SecretTypeCA,
  1457  	}
  1458  
  1459  	tests := []struct {
  1460  		policies           []*conf_v1.Policy
  1461  		expectedSecretRefs map[string]*secrets.SecretReference
  1462  		wantErr            bool
  1463  		msg                string
  1464  	}{
  1465  		{
  1466  			policies: []*conf_v1.Policy{
  1467  				{
  1468  					ObjectMeta: meta_v1.ObjectMeta{
  1469  						Name:      "egress-mtls-policy",
  1470  						Namespace: "default",
  1471  					},
  1472  					Spec: conf_v1.PolicySpec{
  1473  						EgressMTLS: &conf_v1.EgressMTLS{
  1474  							TLSSecret: "valid-egress-mtls-secret",
  1475  						},
  1476  					},
  1477  				},
  1478  			},
  1479  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1480  				"default/valid-egress-mtls-secret": {
  1481  					Secret: validMTLSSecret,
  1482  					Path:   "/etc/nginx/secrets/default-valid-egress-mtls-secret",
  1483  				},
  1484  			},
  1485  			wantErr: false,
  1486  			msg:     "test getting valid TLS secret",
  1487  		},
  1488  		{
  1489  			policies: []*conf_v1.Policy{
  1490  				{
  1491  					ObjectMeta: meta_v1.ObjectMeta{
  1492  						Name:      "egress-egress-trusted-policy",
  1493  						Namespace: "default",
  1494  					},
  1495  					Spec: conf_v1.PolicySpec{
  1496  						EgressMTLS: &conf_v1.EgressMTLS{
  1497  							TrustedCertSecret: "valid-egress-trusted-secret",
  1498  						},
  1499  					},
  1500  				},
  1501  			},
  1502  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1503  				"default/valid-egress-trusted-secret": {
  1504  					Secret: validTrustedSecret,
  1505  					Path:   "/etc/nginx/secrets/default-valid-egress-trusted-secret",
  1506  				},
  1507  			},
  1508  			wantErr: false,
  1509  			msg:     "test getting valid TrustedCA secret",
  1510  		},
  1511  		{
  1512  			policies: []*conf_v1.Policy{
  1513  				{
  1514  					ObjectMeta: meta_v1.ObjectMeta{
  1515  						Name:      "egress-mtls-policy",
  1516  						Namespace: "default",
  1517  					},
  1518  					Spec: conf_v1.PolicySpec{
  1519  						EgressMTLS: &conf_v1.EgressMTLS{
  1520  							TLSSecret:         "valid-egress-mtls-secret",
  1521  							TrustedCertSecret: "valid-egress-trusted-secret",
  1522  						},
  1523  					},
  1524  				},
  1525  			},
  1526  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1527  				"default/valid-egress-mtls-secret": {
  1528  					Secret: validMTLSSecret,
  1529  					Path:   "/etc/nginx/secrets/default-valid-egress-mtls-secret",
  1530  				},
  1531  				"default/valid-egress-trusted-secret": {
  1532  					Secret: validTrustedSecret,
  1533  					Path:   "/etc/nginx/secrets/default-valid-egress-trusted-secret",
  1534  				},
  1535  			},
  1536  			wantErr: false,
  1537  			msg:     "test getting valid secrets",
  1538  		},
  1539  		{
  1540  			policies:           []*conf_v1.Policy{},
  1541  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1542  			wantErr:            false,
  1543  			msg:                "test getting valid secret with no policy",
  1544  		},
  1545  		{
  1546  			policies: []*conf_v1.Policy{
  1547  				{
  1548  					ObjectMeta: meta_v1.ObjectMeta{
  1549  						Name:      "ingress-mtls-policy",
  1550  						Namespace: "default",
  1551  					},
  1552  					Spec: conf_v1.PolicySpec{
  1553  						AccessControl: &conf_v1.AccessControl{
  1554  							Allow: []string{"127.0.0.1"},
  1555  						},
  1556  					},
  1557  				},
  1558  			},
  1559  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1560  			wantErr:            false,
  1561  			msg:                "test getting valid secret with wrong policy",
  1562  		},
  1563  		{
  1564  			policies: []*conf_v1.Policy{
  1565  				{
  1566  					ObjectMeta: meta_v1.ObjectMeta{
  1567  						Name:      "egress-mtls-policy",
  1568  						Namespace: "default",
  1569  					},
  1570  					Spec: conf_v1.PolicySpec{
  1571  						EgressMTLS: &conf_v1.EgressMTLS{
  1572  							TLSSecret: "invalid-egress-mtls-secret",
  1573  						},
  1574  					},
  1575  				},
  1576  			},
  1577  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1578  				"default/invalid-egress-mtls-secret": {
  1579  					Secret: invalidMTLSSecret,
  1580  					Error:  invalidErr,
  1581  				},
  1582  			},
  1583  			wantErr: true,
  1584  			msg:     "test getting invalid TLS secret",
  1585  		},
  1586  		{
  1587  			policies: []*conf_v1.Policy{
  1588  				{
  1589  					ObjectMeta: meta_v1.ObjectMeta{
  1590  						Name:      "egress-mtls-policy",
  1591  						Namespace: "default",
  1592  					},
  1593  					Spec: conf_v1.PolicySpec{
  1594  						EgressMTLS: &conf_v1.EgressMTLS{
  1595  							TrustedCertSecret: "invalid-egress-trusted-secret",
  1596  						},
  1597  					},
  1598  				},
  1599  			},
  1600  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1601  				"default/invalid-egress-trusted-secret": {
  1602  					Secret: invalidTrustedSecret,
  1603  					Error:  invalidErr,
  1604  				},
  1605  			},
  1606  			wantErr: true,
  1607  			msg:     "test getting invalid TrustedCA secret",
  1608  		},
  1609  	}
  1610  
  1611  	lbc := LoadBalancerController{
  1612  		secretStore: secrets.NewFakeSecretsStore(map[string]*secrets.SecretReference{
  1613  			"default/valid-egress-mtls-secret": {
  1614  				Secret: validMTLSSecret,
  1615  				Path:   "/etc/nginx/secrets/default-valid-egress-mtls-secret",
  1616  			},
  1617  			"default/valid-egress-trusted-secret": {
  1618  				Secret: validTrustedSecret,
  1619  				Path:   "/etc/nginx/secrets/default-valid-egress-trusted-secret",
  1620  			},
  1621  			"default/invalid-egress-mtls-secret": {
  1622  				Secret: invalidMTLSSecret,
  1623  				Error:  invalidErr,
  1624  			},
  1625  			"default/invalid-egress-trusted-secret": {
  1626  				Secret: invalidTrustedSecret,
  1627  				Error:  invalidErr,
  1628  			},
  1629  		}),
  1630  	}
  1631  
  1632  	for _, test := range tests {
  1633  		result := make(map[string]*secrets.SecretReference)
  1634  
  1635  		err := lbc.addEgressMTLSSecretRefs(result, test.policies)
  1636  		if (err != nil) != test.wantErr {
  1637  			t.Errorf("addEgressMTLSSecretRefs() returned %v, for the case of %v", err, test.msg)
  1638  		}
  1639  		if diff := cmp.Diff(test.expectedSecretRefs, result, cmp.Comparer(errorComparer)); diff != "" {
  1640  			t.Errorf("addEgressMTLSSecretRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1641  		}
  1642  	}
  1643  }
  1644  
  1645  func TestAddOidcSecret(t *testing.T) {
  1646  	invalidErr := errors.New("invalid")
  1647  	validSecret := &v1.Secret{
  1648  		ObjectMeta: meta_v1.ObjectMeta{
  1649  			Name:      "valid-oidc-secret",
  1650  			Namespace: "default",
  1651  		},
  1652  		Data: map[string][]byte{
  1653  			"client-secret": nil,
  1654  		},
  1655  		Type: secrets.SecretTypeOIDC,
  1656  	}
  1657  	invalidSecret := &v1.Secret{
  1658  		ObjectMeta: meta_v1.ObjectMeta{
  1659  			Name:      "invalid-oidc-secret",
  1660  			Namespace: "default",
  1661  		},
  1662  		Type: secrets.SecretTypeOIDC,
  1663  	}
  1664  
  1665  	tests := []struct {
  1666  		policies           []*conf_v1.Policy
  1667  		expectedSecretRefs map[string]*secrets.SecretReference
  1668  		wantErr            bool
  1669  		msg                string
  1670  	}{
  1671  		{
  1672  			policies: []*conf_v1.Policy{
  1673  				{
  1674  					ObjectMeta: meta_v1.ObjectMeta{
  1675  						Name:      "oidc-policy",
  1676  						Namespace: "default",
  1677  					},
  1678  					Spec: conf_v1.PolicySpec{
  1679  						OIDC: &conf_v1.OIDC{
  1680  							ClientSecret: "valid-oidc-secret",
  1681  						},
  1682  					},
  1683  				},
  1684  			},
  1685  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1686  				"default/valid-oidc-secret": {
  1687  					Secret: validSecret,
  1688  				},
  1689  			},
  1690  			wantErr: false,
  1691  			msg:     "test getting valid secret",
  1692  		},
  1693  		{
  1694  			policies:           []*conf_v1.Policy{},
  1695  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1696  			wantErr:            false,
  1697  			msg:                "test getting valid secret with no policy",
  1698  		},
  1699  		{
  1700  			policies: []*conf_v1.Policy{
  1701  				{
  1702  					ObjectMeta: meta_v1.ObjectMeta{
  1703  						Name:      "oidc-policy",
  1704  						Namespace: "default",
  1705  					},
  1706  					Spec: conf_v1.PolicySpec{
  1707  						AccessControl: &conf_v1.AccessControl{
  1708  							Allow: []string{"127.0.0.1"},
  1709  						},
  1710  					},
  1711  				},
  1712  			},
  1713  			expectedSecretRefs: map[string]*secrets.SecretReference{},
  1714  			wantErr:            false,
  1715  			msg:                "test getting valid secret with wrong policy",
  1716  		},
  1717  		{
  1718  			policies: []*conf_v1.Policy{
  1719  				{
  1720  					ObjectMeta: meta_v1.ObjectMeta{
  1721  						Name:      "oidc-policy",
  1722  						Namespace: "default",
  1723  					},
  1724  					Spec: conf_v1.PolicySpec{
  1725  						OIDC: &conf_v1.OIDC{
  1726  							ClientSecret: "invalid-oidc-secret",
  1727  						},
  1728  					},
  1729  				},
  1730  			},
  1731  			expectedSecretRefs: map[string]*secrets.SecretReference{
  1732  				"default/invalid-oidc-secret": {
  1733  					Secret: invalidSecret,
  1734  					Error:  invalidErr,
  1735  				},
  1736  			},
  1737  			wantErr: true,
  1738  			msg:     "test getting invalid secret",
  1739  		},
  1740  	}
  1741  
  1742  	lbc := LoadBalancerController{
  1743  		secretStore: secrets.NewFakeSecretsStore(map[string]*secrets.SecretReference{
  1744  			"default/valid-oidc-secret": {
  1745  				Secret: validSecret,
  1746  			},
  1747  			"default/invalid-oidc-secret": {
  1748  				Secret: invalidSecret,
  1749  				Error:  invalidErr,
  1750  			},
  1751  		}),
  1752  	}
  1753  
  1754  	for _, test := range tests {
  1755  		result := make(map[string]*secrets.SecretReference)
  1756  
  1757  		err := lbc.addOIDCSecretRefs(result, test.policies)
  1758  		if (err != nil) != test.wantErr {
  1759  			t.Errorf("addOIDCSecretRefs() returned %v, for the case of %v", err, test.msg)
  1760  		}
  1761  
  1762  		if diff := cmp.Diff(test.expectedSecretRefs, result, cmp.Comparer(errorComparer)); diff != "" {
  1763  			t.Errorf("addOIDCSecretRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1764  		}
  1765  	}
  1766  }
  1767  
  1768  func TestAddWAFPolicyRefs(t *testing.T) {
  1769  	apPol := &unstructured.Unstructured{
  1770  		Object: map[string]interface{}{
  1771  			"metadata": map[string]interface{}{
  1772  				"namespace": "default",
  1773  				"name":      "ap-pol",
  1774  			},
  1775  		},
  1776  	}
  1777  
  1778  	logConf := &unstructured.Unstructured{
  1779  		Object: map[string]interface{}{
  1780  			"metadata": map[string]interface{}{
  1781  				"namespace": "default",
  1782  				"name":      "log-conf",
  1783  			},
  1784  		},
  1785  	}
  1786  
  1787  	tests := []struct {
  1788  		policies            []*conf_v1.Policy
  1789  		expectedApPolRefs   map[string]*unstructured.Unstructured
  1790  		expectedLogConfRefs map[string]*unstructured.Unstructured
  1791  		wantErr             bool
  1792  		msg                 string
  1793  	}{
  1794  		{
  1795  			policies: []*conf_v1.Policy{
  1796  				{
  1797  					ObjectMeta: meta_v1.ObjectMeta{
  1798  						Name:      "waf-pol",
  1799  						Namespace: "default",
  1800  					},
  1801  					Spec: conf_v1.PolicySpec{
  1802  						WAF: &conf_v1.WAF{
  1803  							Enable:   true,
  1804  							ApPolicy: "default/ap-pol",
  1805  							SecurityLog: &conf_v1.SecurityLog{
  1806  								Enable:    true,
  1807  								ApLogConf: "log-conf",
  1808  							},
  1809  						},
  1810  					},
  1811  				},
  1812  			},
  1813  			expectedApPolRefs: map[string]*unstructured.Unstructured{
  1814  				"default/ap-pol": apPol,
  1815  			},
  1816  			expectedLogConfRefs: map[string]*unstructured.Unstructured{
  1817  				"default/log-conf": logConf,
  1818  			},
  1819  			wantErr: false,
  1820  			msg:     "base test",
  1821  		},
  1822  		{
  1823  			policies: []*conf_v1.Policy{
  1824  				{
  1825  					ObjectMeta: meta_v1.ObjectMeta{
  1826  						Name:      "waf-pol",
  1827  						Namespace: "default",
  1828  					},
  1829  					Spec: conf_v1.PolicySpec{
  1830  						WAF: &conf_v1.WAF{
  1831  							Enable:   true,
  1832  							ApPolicy: "non-existing-ap-pol",
  1833  						},
  1834  					},
  1835  				},
  1836  			},
  1837  			wantErr:             true,
  1838  			expectedApPolRefs:   make(map[string]*unstructured.Unstructured),
  1839  			expectedLogConfRefs: make(map[string]*unstructured.Unstructured),
  1840  			msg:                 "apPol doesn't exist",
  1841  		},
  1842  		{
  1843  			policies: []*conf_v1.Policy{
  1844  				{
  1845  					ObjectMeta: meta_v1.ObjectMeta{
  1846  						Name:      "waf-pol",
  1847  						Namespace: "default",
  1848  					},
  1849  					Spec: conf_v1.PolicySpec{
  1850  						WAF: &conf_v1.WAF{
  1851  							Enable:   true,
  1852  							ApPolicy: "ap-pol",
  1853  							SecurityLog: &conf_v1.SecurityLog{
  1854  								Enable:    true,
  1855  								ApLogConf: "non-existing-log-conf",
  1856  							},
  1857  						},
  1858  					},
  1859  				},
  1860  			},
  1861  			wantErr: true,
  1862  			expectedApPolRefs: map[string]*unstructured.Unstructured{
  1863  				"default/ap-pol": apPol,
  1864  			},
  1865  			expectedLogConfRefs: make(map[string]*unstructured.Unstructured),
  1866  			msg:                 "logConf doesn't exist",
  1867  		},
  1868  	}
  1869  
  1870  	lbc := LoadBalancerController{
  1871  		appProtectConfiguration: appprotect.NewFakeConfiguration(),
  1872  	}
  1873  	lbc.appProtectConfiguration.AddOrUpdatePolicy(apPol)
  1874  	lbc.appProtectConfiguration.AddOrUpdateLogConf(logConf)
  1875  
  1876  	for _, test := range tests {
  1877  		resApPolicy := make(map[string]*unstructured.Unstructured)
  1878  		resLogConf := make(map[string]*unstructured.Unstructured)
  1879  
  1880  		if err := lbc.addWAFPolicyRefs(resApPolicy, resLogConf, test.policies); (err != nil) != test.wantErr {
  1881  			t.Errorf("LoadBalancerController.addWAFPolicyRefs() error = %v, wantErr %v", err, test.wantErr)
  1882  		}
  1883  		if diff := cmp.Diff(test.expectedApPolRefs, resApPolicy); diff != "" {
  1884  			t.Errorf("LoadBalancerController.addWAFPolicyRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1885  		}
  1886  		if diff := cmp.Diff(test.expectedLogConfRefs, resLogConf); diff != "" {
  1887  			t.Errorf("LoadBalancerController.addWAFPolicyRefs() '%v' mismatch (-want +got):\n%s", test.msg, diff)
  1888  		}
  1889  	}
  1890  }
  1891  
  1892  func TestGetWAFPoliciesForAppProtectPolicy(t *testing.T) {
  1893  	apPol := &conf_v1.Policy{
  1894  		Spec: conf_v1.PolicySpec{
  1895  			WAF: &conf_v1.WAF{
  1896  				Enable:   true,
  1897  				ApPolicy: "ns1/apPol",
  1898  			},
  1899  		},
  1900  	}
  1901  
  1902  	apPolNs2 := &conf_v1.Policy{
  1903  		ObjectMeta: meta_v1.ObjectMeta{
  1904  			Namespace: "ns1",
  1905  		},
  1906  		Spec: conf_v1.PolicySpec{
  1907  			WAF: &conf_v1.WAF{
  1908  				Enable:   true,
  1909  				ApPolicy: "ns2/apPol",
  1910  			},
  1911  		},
  1912  	}
  1913  
  1914  	apPolNoNs := &conf_v1.Policy{
  1915  		ObjectMeta: meta_v1.ObjectMeta{
  1916  			Namespace: "default",
  1917  		},
  1918  		Spec: conf_v1.PolicySpec{
  1919  			WAF: &conf_v1.WAF{
  1920  				Enable:   true,
  1921  				ApPolicy: "apPol",
  1922  			},
  1923  		},
  1924  	}
  1925  
  1926  	policies := []*conf_v1.Policy{
  1927  		apPol, apPolNs2, apPolNoNs,
  1928  	}
  1929  
  1930  	tests := []struct {
  1931  		pols []*conf_v1.Policy
  1932  		key  string
  1933  		want []*conf_v1.Policy
  1934  		msg  string
  1935  	}{
  1936  		{
  1937  			pols: policies,
  1938  			key:  "ns1/apPol",
  1939  			want: []*conf_v1.Policy{apPol},
  1940  			msg:  "WAF pols that ref apPol which has a namepace",
  1941  		},
  1942  		{
  1943  			pols: policies,
  1944  			key:  "default/apPol",
  1945  			want: []*conf_v1.Policy{apPolNoNs},
  1946  			msg:  "WAF pols that ref apPol which has no namepace",
  1947  		},
  1948  		{
  1949  			pols: policies,
  1950  			key:  "ns2/apPol",
  1951  			want: []*conf_v1.Policy{apPolNs2},
  1952  			msg:  "WAF pols that ref apPol which is in another ns",
  1953  		},
  1954  		{
  1955  			pols: policies,
  1956  			key:  "ns1/apPol-with-no-valid-refs",
  1957  			want: nil,
  1958  			msg:  "WAF pols where there is no valid ref",
  1959  		},
  1960  	}
  1961  	for _, test := range tests {
  1962  		got := getWAFPoliciesForAppProtectPolicy(test.pols, test.key)
  1963  		if diff := cmp.Diff(test.want, got); diff != "" {
  1964  			t.Errorf("getWAFPoliciesForAppProtectPolicy() returned unexpected result for the case of: %v (-want +got):\n%s", test.msg, diff)
  1965  		}
  1966  	}
  1967  }
  1968  
  1969  func TestGetWAFPoliciesForAppProtectLogConf(t *testing.T) {
  1970  	logConf := &conf_v1.Policy{
  1971  		Spec: conf_v1.PolicySpec{
  1972  			WAF: &conf_v1.WAF{
  1973  				Enable: true,
  1974  				SecurityLog: &conf_v1.SecurityLog{
  1975  					Enable:    true,
  1976  					ApLogConf: "ns1/logConf",
  1977  				},
  1978  			},
  1979  		},
  1980  	}
  1981  
  1982  	logConfNs2 := &conf_v1.Policy{
  1983  		ObjectMeta: meta_v1.ObjectMeta{
  1984  			Namespace: "ns1",
  1985  		},
  1986  		Spec: conf_v1.PolicySpec{
  1987  			WAF: &conf_v1.WAF{
  1988  				Enable: true,
  1989  				SecurityLog: &conf_v1.SecurityLog{
  1990  					Enable:    true,
  1991  					ApLogConf: "ns2/logConf",
  1992  				},
  1993  			},
  1994  		},
  1995  	}
  1996  
  1997  	logConfNoNs := &conf_v1.Policy{
  1998  		ObjectMeta: meta_v1.ObjectMeta{
  1999  			Namespace: "default",
  2000  		},
  2001  		Spec: conf_v1.PolicySpec{
  2002  			WAF: &conf_v1.WAF{
  2003  				Enable: true,
  2004  				SecurityLog: &conf_v1.SecurityLog{
  2005  					Enable:    true,
  2006  					ApLogConf: "logConf",
  2007  				},
  2008  			},
  2009  		},
  2010  	}
  2011  
  2012  	policies := []*conf_v1.Policy{
  2013  		logConf, logConfNs2, logConfNoNs,
  2014  	}
  2015  
  2016  	tests := []struct {
  2017  		pols []*conf_v1.Policy
  2018  		key  string
  2019  		want []*conf_v1.Policy
  2020  		msg  string
  2021  	}{
  2022  		{
  2023  			pols: policies,
  2024  			key:  "ns1/logConf",
  2025  			want: []*conf_v1.Policy{logConf},
  2026  			msg:  "WAF pols that ref logConf which has a namepace",
  2027  		},
  2028  		{
  2029  			pols: policies,
  2030  			key:  "default/logConf",
  2031  			want: []*conf_v1.Policy{logConfNoNs},
  2032  			msg:  "WAF pols that ref logConf which has no namepace",
  2033  		},
  2034  		{
  2035  			pols: policies,
  2036  			key:  "ns2/logConf",
  2037  			want: []*conf_v1.Policy{logConfNs2},
  2038  			msg:  "WAF pols that ref logConf which is in another ns",
  2039  		},
  2040  		{
  2041  			pols: policies,
  2042  			key:  "ns1/logConf-with-no-valid-refs",
  2043  			want: nil,
  2044  			msg:  "WAF pols where there is no valid logConf ref",
  2045  		},
  2046  	}
  2047  	for _, test := range tests {
  2048  		got := getWAFPoliciesForAppProtectLogConf(test.pols, test.key)
  2049  		if diff := cmp.Diff(test.want, got); diff != "" {
  2050  			t.Errorf("getWAFPoliciesForAppProtectLogConf() returned unexpected result for the case of: %v (-want +got):\n%s", test.msg, diff)
  2051  		}
  2052  	}
  2053  }
  2054  
  2055  func TestPreSyncSecrets(t *testing.T) {
  2056  	lbc := LoadBalancerController{
  2057  		isNginxPlus: true,
  2058  		secretStore: secrets.NewEmptyFakeSecretsStore(),
  2059  		secretLister: &cache.FakeCustomStore{
  2060  			ListFunc: func() []interface{} {
  2061  				return []interface{}{
  2062  					&api_v1.Secret{
  2063  						ObjectMeta: meta_v1.ObjectMeta{
  2064  							Name:      "supported-secret",
  2065  							Namespace: "default",
  2066  						},
  2067  						Type: api_v1.SecretTypeTLS,
  2068  					},
  2069  					&api_v1.Secret{
  2070  						ObjectMeta: meta_v1.ObjectMeta{
  2071  							Name:      "unsupported-secret",
  2072  							Namespace: "default",
  2073  						},
  2074  						Type: api_v1.SecretTypeOpaque,
  2075  					},
  2076  				}
  2077  			},
  2078  		},
  2079  	}
  2080  
  2081  	lbc.preSyncSecrets()
  2082  
  2083  	supportedKey := "default/supported-secret"
  2084  	ref := lbc.secretStore.GetSecret(supportedKey)
  2085  	if ref.Error != nil {
  2086  		t.Errorf("GetSecret(%q) returned a reference with an unexpected error %v", supportedKey, ref.Error)
  2087  	}
  2088  
  2089  	unsupportedKey := "default/unsupported-secret"
  2090  	ref = lbc.secretStore.GetSecret(unsupportedKey)
  2091  	if ref.Error == nil {
  2092  		t.Errorf("GetSecret(%q) returned a reference without an expected error", unsupportedKey)
  2093  	}
  2094  }