sigs.k8s.io/external-dns@v0.14.1/source/ingress_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package source
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  	"github.com/stretchr/testify/suite"
    26  	networkv1 "k8s.io/api/networking/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/labels"
    29  	"k8s.io/client-go/kubernetes/fake"
    30  
    31  	"sigs.k8s.io/external-dns/endpoint"
    32  )
    33  
    34  // Validates that ingressSource is a Source
    35  var _ Source = &ingressSource{}
    36  
    37  type IngressSuite struct {
    38  	suite.Suite
    39  	sc             Source
    40  	fooWithTargets *networkv1.Ingress
    41  }
    42  
    43  func (suite *IngressSuite) SetupTest() {
    44  	fakeClient := fake.NewSimpleClientset()
    45  
    46  	suite.fooWithTargets = (fakeIngress{
    47  		name:        "foo-with-targets",
    48  		namespace:   "default",
    49  		dnsnames:    []string{"foo"},
    50  		ips:         []string{"8.8.8.8"},
    51  		hostnames:   []string{"v1"},
    52  		annotations: map[string]string{ALBDualstackAnnotationKey: ALBDualstackAnnotationValue},
    53  	}).Ingress()
    54  	_, err := fakeClient.NetworkingV1().Ingresses(suite.fooWithTargets.Namespace).Create(context.Background(), suite.fooWithTargets, metav1.CreateOptions{})
    55  	suite.NoError(err, "should succeed")
    56  
    57  	suite.sc, err = NewIngressSource(
    58  		context.TODO(),
    59  		fakeClient,
    60  		"",
    61  		"",
    62  		"{{.Name}}",
    63  		false,
    64  		false,
    65  		false,
    66  		false,
    67  		labels.Everything(),
    68  		[]string{},
    69  	)
    70  	suite.NoError(err, "should initialize ingress source")
    71  }
    72  
    73  func (suite *IngressSuite) TestResourceLabelIsSet() {
    74  	endpoints, _ := suite.sc.Endpoints(context.Background())
    75  	for _, ep := range endpoints {
    76  		suite.Equal("ingress/default/foo-with-targets", ep.Labels[endpoint.ResourceLabelKey], "should set correct resource label")
    77  	}
    78  }
    79  
    80  func (suite *IngressSuite) TestDualstackLabelIsSet() {
    81  	endpoints, _ := suite.sc.Endpoints(context.Background())
    82  	for _, ep := range endpoints {
    83  		suite.Equal("true", ep.Labels[endpoint.DualstackLabelKey], "should set dualstack label to true")
    84  	}
    85  }
    86  
    87  func TestIngress(t *testing.T) {
    88  	t.Parallel()
    89  
    90  	suite.Run(t, new(IngressSuite))
    91  	t.Run("endpointsFromIngress", testEndpointsFromIngress)
    92  	t.Run("endpointsFromIngressHostnameSourceAnnotation", testEndpointsFromIngressHostnameSourceAnnotation)
    93  	t.Run("Endpoints", testIngressEndpoints)
    94  }
    95  
    96  func TestNewIngressSource(t *testing.T) {
    97  	t.Parallel()
    98  
    99  	for _, ti := range []struct {
   100  		title                    string
   101  		annotationFilter         string
   102  		fqdnTemplate             string
   103  		combineFQDNAndAnnotation bool
   104  		expectError              bool
   105  		ingressClassNames        []string
   106  	}{
   107  		{
   108  			title:        "invalid template",
   109  			expectError:  true,
   110  			fqdnTemplate: "{{.Name",
   111  		},
   112  		{
   113  			title:       "valid empty template",
   114  			expectError: false,
   115  		},
   116  		{
   117  			title:        "valid template",
   118  			expectError:  false,
   119  			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
   120  		},
   121  		{
   122  			title:        "valid template",
   123  			expectError:  false,
   124  			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
   125  		},
   126  		{
   127  			title:                    "valid template",
   128  			expectError:              false,
   129  			fqdnTemplate:             "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
   130  			combineFQDNAndAnnotation: true,
   131  		},
   132  		{
   133  			title:            "non-empty annotation filter label",
   134  			expectError:      false,
   135  			annotationFilter: "kubernetes.io/ingress.class=nginx",
   136  		},
   137  		{
   138  			title:             "non-empty ingress class name list",
   139  			expectError:       false,
   140  			ingressClassNames: []string{"internal", "external"},
   141  		},
   142  		{
   143  			title:             "ingress class name and annotation filter jointly specified",
   144  			expectError:       true,
   145  			ingressClassNames: []string{"internal", "external"},
   146  			annotationFilter:  "kubernetes.io/ingress.class=nginx",
   147  		},
   148  	} {
   149  		ti := ti
   150  		t.Run(ti.title, func(t *testing.T) {
   151  			t.Parallel()
   152  
   153  			_, err := NewIngressSource(
   154  				context.TODO(),
   155  				fake.NewSimpleClientset(),
   156  				"",
   157  				ti.annotationFilter,
   158  				ti.fqdnTemplate,
   159  				ti.combineFQDNAndAnnotation,
   160  				false,
   161  				false,
   162  				false,
   163  				labels.Everything(),
   164  				ti.ingressClassNames,
   165  			)
   166  			if ti.expectError {
   167  				assert.Error(t, err)
   168  			} else {
   169  				assert.NoError(t, err)
   170  			}
   171  		})
   172  	}
   173  }
   174  
   175  func testEndpointsFromIngress(t *testing.T) {
   176  	t.Parallel()
   177  
   178  	for _, ti := range []struct {
   179  		title                    string
   180  		ingress                  fakeIngress
   181  		ignoreHostnameAnnotation bool
   182  		ignoreIngressTLSSpec     bool
   183  		ignoreIngressRulesSpec   bool
   184  		expected                 []*endpoint.Endpoint
   185  	}{
   186  		{
   187  			title: "one rule.host one lb.hostname",
   188  			ingress: fakeIngress{
   189  				dnsnames:  []string{"foo.bar"}, // Kubernetes requires removal of trailing dot
   190  				hostnames: []string{"lb.com"},  // Kubernetes omits the trailing dot
   191  			},
   192  			expected: []*endpoint.Endpoint{
   193  				{
   194  					DNSName:    "foo.bar",
   195  					RecordType: endpoint.RecordTypeCNAME,
   196  					Targets:    endpoint.Targets{"lb.com"},
   197  				},
   198  			},
   199  		},
   200  		{
   201  			title: "one rule.host one lb.IP",
   202  			ingress: fakeIngress{
   203  				dnsnames: []string{"foo.bar"},
   204  				ips:      []string{"8.8.8.8"},
   205  			},
   206  			expected: []*endpoint.Endpoint{
   207  				{
   208  					DNSName:    "foo.bar",
   209  					RecordType: endpoint.RecordTypeA,
   210  					Targets:    endpoint.Targets{"8.8.8.8"},
   211  				},
   212  			},
   213  		},
   214  		{
   215  			title: "one rule.host two lb.IP and two lb.Hostname",
   216  			ingress: fakeIngress{
   217  				dnsnames:  []string{"foo.bar"},
   218  				ips:       []string{"8.8.8.8", "127.0.0.1"},
   219  				hostnames: []string{"elb.com", "alb.com"},
   220  			},
   221  			expected: []*endpoint.Endpoint{
   222  				{
   223  					DNSName:    "foo.bar",
   224  					RecordType: endpoint.RecordTypeA,
   225  					Targets:    endpoint.Targets{"8.8.8.8", "127.0.0.1"},
   226  				},
   227  				{
   228  					DNSName:    "foo.bar",
   229  					RecordType: endpoint.RecordTypeCNAME,
   230  					Targets:    endpoint.Targets{"elb.com", "alb.com"},
   231  				},
   232  			},
   233  		},
   234  		{
   235  			title: "no rule.host",
   236  			ingress: fakeIngress{
   237  				ips:       []string{"8.8.8.8", "127.0.0.1"},
   238  				hostnames: []string{"elb.com", "alb.com"},
   239  			},
   240  			expected: []*endpoint.Endpoint{},
   241  		},
   242  		{
   243  			title: "one empty rule.host",
   244  			ingress: fakeIngress{
   245  				dnsnames:  []string{""},
   246  				ips:       []string{"8.8.8.8", "127.0.0.1"},
   247  				hostnames: []string{"elb.com", "alb.com"},
   248  			},
   249  			expected: []*endpoint.Endpoint{},
   250  		},
   251  		{
   252  			title: "no targets",
   253  			ingress: fakeIngress{
   254  				dnsnames: []string{""},
   255  			},
   256  			expected: []*endpoint.Endpoint{},
   257  		},
   258  		{
   259  			title: "ignore rules with one rule.host one lb.hostname",
   260  			ingress: fakeIngress{
   261  				dnsnames:  []string{"test"},   // Kubernetes requires removal of trailing dot
   262  				hostnames: []string{"lb.com"}, // Kubernetes omits the trailing dot
   263  			},
   264  			expected:               []*endpoint.Endpoint{},
   265  			ignoreIngressRulesSpec: true,
   266  		},
   267  		{
   268  			title: "invalid hostname does not generate endpoints",
   269  			ingress: fakeIngress{
   270  				dnsnames:  []string{"this-is-an-exceedingly-long-label-that-external-dns-should-reject.example.org"},
   271  			},
   272  			expected: []*endpoint.Endpoint{},
   273  		},
   274  	} {
   275  		t.Run(ti.title, func(t *testing.T) {
   276  			realIngress := ti.ingress.Ingress()
   277  			validateEndpoints(t, endpointsFromIngress(realIngress, ti.ignoreHostnameAnnotation, ti.ignoreIngressTLSSpec, ti.ignoreIngressRulesSpec), ti.expected)
   278  		})
   279  	}
   280  }
   281  
   282  func testEndpointsFromIngressHostnameSourceAnnotation(t *testing.T) {
   283  	// Host names and host name annotation provided, with various values of the ingress-hostname-source annotation
   284  	for _, ti := range []struct {
   285  		title    string
   286  		ingress  fakeIngress
   287  		expected []*endpoint.Endpoint
   288  	}{
   289  		{
   290  			title: "No ingress-hostname-source annotation, one rule.host, one annotation host",
   291  			ingress: fakeIngress{
   292  				dnsnames:    []string{"foo.bar"},
   293  				annotations: map[string]string{hostnameAnnotationKey: "foo.baz"},
   294  				hostnames:   []string{"lb.com"},
   295  			},
   296  			expected: []*endpoint.Endpoint{
   297  				{
   298  					DNSName:    "foo.bar",
   299  					RecordType: endpoint.RecordTypeCNAME,
   300  					Targets:    endpoint.Targets{"lb.com"},
   301  				},
   302  				{
   303  					DNSName:    "foo.baz",
   304  					RecordType: endpoint.RecordTypeCNAME,
   305  					Targets:    endpoint.Targets{"lb.com"},
   306  				},
   307  			},
   308  		},
   309  		{
   310  			title: "No ingress-hostname-source annotation, one rule.host",
   311  			ingress: fakeIngress{
   312  				dnsnames:  []string{"foo.bar"},
   313  				hostnames: []string{"lb.com"},
   314  			},
   315  			expected: []*endpoint.Endpoint{
   316  				{
   317  					DNSName:    "foo.bar",
   318  					RecordType: endpoint.RecordTypeCNAME,
   319  					Targets:    endpoint.Targets{"lb.com"},
   320  				},
   321  			},
   322  		},
   323  		{
   324  			title: "No ingress-hostname-source annotation, one rule.host, one annotation host",
   325  			ingress: fakeIngress{
   326  				dnsnames:    []string{"foo.bar"},
   327  				annotations: map[string]string{hostnameAnnotationKey: "foo.baz"},
   328  				hostnames:   []string{"lb.com"},
   329  			},
   330  			expected: []*endpoint.Endpoint{
   331  				{
   332  					DNSName:    "foo.bar",
   333  					RecordType: endpoint.RecordTypeCNAME,
   334  					Targets:    endpoint.Targets{"lb.com"},
   335  				},
   336  				{
   337  					DNSName:    "foo.baz",
   338  					RecordType: endpoint.RecordTypeCNAME,
   339  					Targets:    endpoint.Targets{"lb.com"},
   340  				},
   341  			},
   342  		},
   343  		{
   344  			title: "Ingress-hostname-source=defined-hosts-only, one rule.host, one annotation host",
   345  			ingress: fakeIngress{
   346  				dnsnames:    []string{"foo.bar"},
   347  				annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "defined-hosts-only"},
   348  				hostnames:   []string{"lb.com"},
   349  			},
   350  			expected: []*endpoint.Endpoint{
   351  				{
   352  					DNSName:    "foo.bar",
   353  					RecordType: endpoint.RecordTypeCNAME,
   354  					Targets:    endpoint.Targets{"lb.com"},
   355  				},
   356  			},
   357  		},
   358  		{
   359  			title: "Ingress-hostname-source=annotation-only, one rule.host, one annotation host",
   360  			ingress: fakeIngress{
   361  				dnsnames:    []string{"foo.bar"},
   362  				annotations: map[string]string{hostnameAnnotationKey: "foo.baz", ingressHostnameSourceKey: "annotation-only"},
   363  				hostnames:   []string{"lb.com"},
   364  			},
   365  			expected: []*endpoint.Endpoint{
   366  				{
   367  					DNSName:    "foo.baz",
   368  					RecordType: endpoint.RecordTypeCNAME,
   369  					Targets:    endpoint.Targets{"lb.com"},
   370  				},
   371  			},
   372  		},
   373  	} {
   374  		t.Run(ti.title, func(t *testing.T) {
   375  			realIngress := ti.ingress.Ingress()
   376  			validateEndpoints(t, endpointsFromIngress(realIngress, false, false, false), ti.expected)
   377  		})
   378  	}
   379  }
   380  
   381  func testIngressEndpoints(t *testing.T) {
   382  	t.Parallel()
   383  
   384  	namespace := "testing"
   385  	for _, ti := range []struct {
   386  		title                    string
   387  		targetNamespace          string
   388  		annotationFilter         string
   389  		ingressItems             []fakeIngress
   390  		expected                 []*endpoint.Endpoint
   391  		expectError              bool
   392  		fqdnTemplate             string
   393  		combineFQDNAndAnnotation bool
   394  		ignoreHostnameAnnotation bool
   395  		ignoreIngressTLSSpec     bool
   396  		ignoreIngressRulesSpec   bool
   397  		ingressLabelSelector     labels.Selector
   398  		ingressClassNames        []string
   399  	}{
   400  		{
   401  			title:           "no ingress",
   402  			targetNamespace: "",
   403  		},
   404  		{
   405  			title:           "two simple ingresses",
   406  			targetNamespace: "",
   407  			ingressItems: []fakeIngress{
   408  				{
   409  					name:      "fake1",
   410  					namespace: namespace,
   411  					dnsnames:  []string{"example.org"},
   412  					ips:       []string{"8.8.8.8"},
   413  				},
   414  				{
   415  					name:      "fake2",
   416  					namespace: namespace,
   417  					dnsnames:  []string{"new.org"},
   418  					hostnames: []string{"lb.com"},
   419  				},
   420  			},
   421  			expected: []*endpoint.Endpoint{
   422  				{
   423  					DNSName:    "example.org",
   424  					RecordType: endpoint.RecordTypeA,
   425  					Targets:    endpoint.Targets{"8.8.8.8"},
   426  				},
   427  				{
   428  					DNSName:    "new.org",
   429  					RecordType: endpoint.RecordTypeCNAME,
   430  					Targets:    endpoint.Targets{"lb.com"},
   431  				},
   432  			},
   433  		},
   434  		{
   435  			title:           "ipv6 ingress",
   436  			targetNamespace: "",
   437  			ingressItems: []fakeIngress{
   438  				{
   439  					name:      "fake1",
   440  					namespace: namespace,
   441  					dnsnames:  []string{"example.org"},
   442  					ips:       []string{"2001:DB8::1"},
   443  				},
   444  			},
   445  			expected: []*endpoint.Endpoint{
   446  				{
   447  					DNSName:    "example.org",
   448  					RecordType: endpoint.RecordTypeAAAA,
   449  					Targets:    endpoint.Targets{"2001:DB8::1"},
   450  				},
   451  			},
   452  		},
   453  		{
   454  			title:                  "ignore rules",
   455  			targetNamespace:        "",
   456  			ignoreIngressRulesSpec: true,
   457  			ingressItems: []fakeIngress{
   458  				{
   459  					name:      "fake1",
   460  					namespace: namespace,
   461  					dnsnames:  []string{"example.org"},
   462  					ips:       []string{"8.8.8.8"},
   463  				},
   464  				{
   465  					name:      "fake2",
   466  					namespace: namespace,
   467  					dnsnames:  []string{"new.org"},
   468  					hostnames: []string{"lb.com"},
   469  				},
   470  			},
   471  			expected: []*endpoint.Endpoint{},
   472  		},
   473  		{
   474  			title:           "two simple ingresses on different namespaces",
   475  			targetNamespace: "",
   476  			ingressItems: []fakeIngress{
   477  				{
   478  					name:      "fake1",
   479  					namespace: "testing1",
   480  					dnsnames:  []string{"example.org"},
   481  					ips:       []string{"8.8.8.8"},
   482  				},
   483  				{
   484  					name:      "fake2",
   485  					namespace: "testing2",
   486  					dnsnames:  []string{"new.org"},
   487  					hostnames: []string{"lb.com"},
   488  				},
   489  			},
   490  			expected: []*endpoint.Endpoint{
   491  				{
   492  					DNSName:    "example.org",
   493  					RecordType: endpoint.RecordTypeA,
   494  					Targets:    endpoint.Targets{"8.8.8.8"},
   495  				},
   496  				{
   497  					DNSName:    "new.org",
   498  					RecordType: endpoint.RecordTypeCNAME,
   499  					Targets:    endpoint.Targets{"lb.com"},
   500  				},
   501  			},
   502  		},
   503  		{
   504  			title:           "two simple ingresses on different namespaces with target namespace",
   505  			targetNamespace: "testing1",
   506  			ingressItems: []fakeIngress{
   507  				{
   508  					name:      "fake1",
   509  					namespace: "testing1",
   510  					dnsnames:  []string{"example.org"},
   511  					ips:       []string{"8.8.8.8"},
   512  				},
   513  				{
   514  					name:      "fake2",
   515  					namespace: "testing2",
   516  					dnsnames:  []string{"new.org"},
   517  					hostnames: []string{"lb.com"},
   518  				},
   519  			},
   520  			expected: []*endpoint.Endpoint{
   521  				{
   522  					DNSName:    "example.org",
   523  					RecordType: endpoint.RecordTypeA,
   524  					Targets:    endpoint.Targets{"8.8.8.8"},
   525  				},
   526  			},
   527  		},
   528  		{
   529  			title:            "valid matching annotation filter expression",
   530  			targetNamespace:  "",
   531  			annotationFilter: "kubernetes.io/ingress.class in (alb, nginx)",
   532  			ingressItems: []fakeIngress{
   533  				{
   534  					name:      "fake1",
   535  					namespace: namespace,
   536  					annotations: map[string]string{
   537  						"kubernetes.io/ingress.class": "nginx",
   538  					},
   539  					dnsnames: []string{"example.org"},
   540  					ips:      []string{"8.8.8.8"},
   541  				},
   542  			},
   543  			expected: []*endpoint.Endpoint{
   544  				{
   545  					DNSName:    "example.org",
   546  					RecordType: endpoint.RecordTypeA,
   547  					Targets:    endpoint.Targets{"8.8.8.8"},
   548  				},
   549  			},
   550  		},
   551  		{
   552  			title:            "valid non-matching annotation filter expression",
   553  			targetNamespace:  "",
   554  			annotationFilter: "kubernetes.io/ingress.class in (alb, nginx)",
   555  			ingressItems: []fakeIngress{
   556  				{
   557  					name:      "fake1",
   558  					namespace: namespace,
   559  					annotations: map[string]string{
   560  						"kubernetes.io/ingress.class": "tectonic",
   561  					},
   562  					dnsnames: []string{"example.org"},
   563  					ips:      []string{"8.8.8.8"},
   564  				},
   565  			},
   566  			expected: []*endpoint.Endpoint{},
   567  		},
   568  		{
   569  			title:            "invalid annotation filter expression",
   570  			targetNamespace:  "",
   571  			annotationFilter: "kubernetes.io/ingress.name in (a b)",
   572  			ingressItems: []fakeIngress{
   573  				{
   574  					name:      "fake1",
   575  					namespace: namespace,
   576  					annotations: map[string]string{
   577  						"kubernetes.io/ingress.class": "alb",
   578  					},
   579  					dnsnames: []string{"example.org"},
   580  					ips:      []string{"8.8.8.8"},
   581  				},
   582  			},
   583  			expected:    []*endpoint.Endpoint{},
   584  			expectError: true,
   585  		},
   586  		{
   587  			title:            "valid matching annotation filter label",
   588  			targetNamespace:  "",
   589  			annotationFilter: "kubernetes.io/ingress.class=nginx",
   590  			ingressItems: []fakeIngress{
   591  				{
   592  					name:      "fake1",
   593  					namespace: namespace,
   594  					annotations: map[string]string{
   595  						"kubernetes.io/ingress.class": "nginx",
   596  					},
   597  					dnsnames: []string{"example.org"},
   598  					ips:      []string{"8.8.8.8"},
   599  				},
   600  			},
   601  			expected: []*endpoint.Endpoint{
   602  				{
   603  					DNSName:    "example.org",
   604  					RecordType: endpoint.RecordTypeA,
   605  					Targets:    endpoint.Targets{"8.8.8.8"},
   606  				},
   607  			},
   608  		},
   609  		{
   610  			title:            "valid non-matching annotation filter label",
   611  			targetNamespace:  "",
   612  			annotationFilter: "kubernetes.io/ingress.class=nginx",
   613  			ingressItems: []fakeIngress{
   614  				{
   615  					name:      "fake1",
   616  					namespace: namespace,
   617  					annotations: map[string]string{
   618  						"kubernetes.io/ingress.class": "alb",
   619  					},
   620  					dnsnames: []string{"example.org"},
   621  					ips:      []string{"8.8.8.8"},
   622  				},
   623  			},
   624  			expected: []*endpoint.Endpoint{},
   625  		},
   626  		{
   627  			title:           "our controller type is dns-controller",
   628  			targetNamespace: "",
   629  			ingressItems: []fakeIngress{
   630  				{
   631  					name:      "fake1",
   632  					namespace: namespace,
   633  					annotations: map[string]string{
   634  						controllerAnnotationKey: controllerAnnotationValue,
   635  					},
   636  					dnsnames: []string{"example.org"},
   637  					ips:      []string{"8.8.8.8"},
   638  				},
   639  			},
   640  			expected: []*endpoint.Endpoint{
   641  				{
   642  					DNSName:    "example.org",
   643  					RecordType: endpoint.RecordTypeA,
   644  					Targets:    endpoint.Targets{"8.8.8.8"},
   645  				},
   646  			},
   647  		},
   648  		{
   649  			title:           "different controller types are ignored",
   650  			targetNamespace: "",
   651  			ingressItems: []fakeIngress{
   652  				{
   653  					name:      "fake1",
   654  					namespace: namespace,
   655  					annotations: map[string]string{
   656  						controllerAnnotationKey: "some-other-tool",
   657  					},
   658  					dnsnames: []string{"example.org"},
   659  					ips:      []string{"8.8.8.8"},
   660  				},
   661  			},
   662  			expected: []*endpoint.Endpoint{},
   663  		},
   664  		{
   665  			title:           "template for ingress if host is missing",
   666  			targetNamespace: "",
   667  			ingressItems: []fakeIngress{
   668  				{
   669  					name:      "fake1",
   670  					namespace: namespace,
   671  					annotations: map[string]string{
   672  						controllerAnnotationKey: controllerAnnotationValue,
   673  					},
   674  					dnsnames:  []string{},
   675  					ips:       []string{"8.8.8.8"},
   676  					hostnames: []string{"elb.com"},
   677  				},
   678  			},
   679  			expected: []*endpoint.Endpoint{
   680  				{
   681  					DNSName:    "fake1.ext-dns.test.com",
   682  					RecordType: endpoint.RecordTypeA,
   683  					Targets:    endpoint.Targets{"8.8.8.8"},
   684  				},
   685  				{
   686  					DNSName:    "fake1.ext-dns.test.com",
   687  					RecordType: endpoint.RecordTypeCNAME,
   688  					Targets:    endpoint.Targets{"elb.com"},
   689  				},
   690  			},
   691  			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
   692  		},
   693  		{
   694  			title:           "another controller annotation skipped even with template",
   695  			targetNamespace: "",
   696  			ingressItems: []fakeIngress{
   697  				{
   698  					name:      "fake1",
   699  					namespace: namespace,
   700  					annotations: map[string]string{
   701  						controllerAnnotationKey: "other-controller",
   702  					},
   703  					dnsnames: []string{},
   704  					ips:      []string{"8.8.8.8"},
   705  				},
   706  			},
   707  			expected:     []*endpoint.Endpoint{},
   708  			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
   709  		},
   710  		{
   711  			title:           "multiple FQDN template hostnames",
   712  			targetNamespace: "",
   713  			ingressItems: []fakeIngress{
   714  				{
   715  					name:        "fake1",
   716  					namespace:   namespace,
   717  					annotations: map[string]string{},
   718  					dnsnames:    []string{},
   719  					ips:         []string{"8.8.8.8"},
   720  				},
   721  			},
   722  			expected: []*endpoint.Endpoint{
   723  				{
   724  					DNSName:    "fake1.ext-dns.test.com",
   725  					Targets:    endpoint.Targets{"8.8.8.8"},
   726  					RecordType: endpoint.RecordTypeA,
   727  				},
   728  				{
   729  					DNSName:    "fake1.ext-dna.test.com",
   730  					Targets:    endpoint.Targets{"8.8.8.8"},
   731  					RecordType: endpoint.RecordTypeA,
   732  				},
   733  			},
   734  			fqdnTemplate: "{{.Name}}.ext-dns.test.com, {{.Name}}.ext-dna.test.com",
   735  		},
   736  		{
   737  			title:           "multiple FQDN template hostnames",
   738  			targetNamespace: "",
   739  			ingressItems: []fakeIngress{
   740  				{
   741  					name:        "fake1",
   742  					namespace:   namespace,
   743  					annotations: map[string]string{},
   744  					dnsnames:    []string{},
   745  					ips:         []string{"8.8.8.8"},
   746  				},
   747  				{
   748  					name:      "fake2",
   749  					namespace: namespace,
   750  					annotations: map[string]string{
   751  						targetAnnotationKey: "ingress-target.com",
   752  					},
   753  					dnsnames: []string{"example.org"},
   754  					ips:      []string{},
   755  				},
   756  			},
   757  			expected: []*endpoint.Endpoint{
   758  				{
   759  					DNSName:    "fake1.ext-dns.test.com",
   760  					Targets:    endpoint.Targets{"8.8.8.8"},
   761  					RecordType: endpoint.RecordTypeA,
   762  				},
   763  				{
   764  					DNSName:    "fake1.ext-dna.test.com",
   765  					Targets:    endpoint.Targets{"8.8.8.8"},
   766  					RecordType: endpoint.RecordTypeA,
   767  				},
   768  				{
   769  					DNSName:    "example.org",
   770  					Targets:    endpoint.Targets{"ingress-target.com"},
   771  					RecordType: endpoint.RecordTypeCNAME,
   772  				},
   773  				{
   774  					DNSName:    "fake2.ext-dns.test.com",
   775  					Targets:    endpoint.Targets{"ingress-target.com"},
   776  					RecordType: endpoint.RecordTypeCNAME,
   777  				},
   778  				{
   779  					DNSName:    "fake2.ext-dna.test.com",
   780  					Targets:    endpoint.Targets{"ingress-target.com"},
   781  					RecordType: endpoint.RecordTypeCNAME,
   782  				},
   783  			},
   784  			fqdnTemplate:             "{{.Name}}.ext-dns.test.com, {{.Name}}.ext-dna.test.com",
   785  			combineFQDNAndAnnotation: true,
   786  		},
   787  		{
   788  			title:           "ingress rules with annotation",
   789  			targetNamespace: "",
   790  			ingressItems: []fakeIngress{
   791  				{
   792  					name:      "fake1",
   793  					namespace: namespace,
   794  					annotations: map[string]string{
   795  						targetAnnotationKey: "ingress-target.com",
   796  					},
   797  					dnsnames: []string{"example.org"},
   798  					ips:      []string{},
   799  				},
   800  				{
   801  					name:      "fake2",
   802  					namespace: namespace,
   803  					annotations: map[string]string{
   804  						targetAnnotationKey: "ingress-target.com",
   805  					},
   806  					dnsnames: []string{"example2.org"},
   807  					ips:      []string{"8.8.8.8"},
   808  				},
   809  				{
   810  					name:      "fake3",
   811  					namespace: namespace,
   812  					annotations: map[string]string{
   813  						targetAnnotationKey: "1.2.3.4",
   814  					},
   815  					dnsnames: []string{"example3.org"},
   816  					ips:      []string{},
   817  				},
   818  			},
   819  			expected: []*endpoint.Endpoint{
   820  				{
   821  					DNSName:    "example.org",
   822  					Targets:    endpoint.Targets{"ingress-target.com"},
   823  					RecordType: endpoint.RecordTypeCNAME,
   824  				},
   825  				{
   826  					DNSName:    "example2.org",
   827  					Targets:    endpoint.Targets{"ingress-target.com"},
   828  					RecordType: endpoint.RecordTypeCNAME,
   829  				},
   830  				{
   831  					DNSName:    "example3.org",
   832  					Targets:    endpoint.Targets{"1.2.3.4"},
   833  					RecordType: endpoint.RecordTypeA,
   834  				},
   835  			},
   836  		},
   837  		{
   838  			title:           "ingress rules with single tls having single hostname",
   839  			targetNamespace: "",
   840  			ingressItems: []fakeIngress{
   841  				{
   842  					name:        "fake1",
   843  					namespace:   namespace,
   844  					tlsdnsnames: [][]string{{"example.org"}},
   845  					ips:         []string{"1.2.3.4"},
   846  				},
   847  			},
   848  			expected: []*endpoint.Endpoint{
   849  				{
   850  					DNSName:    "example.org",
   851  					Targets:    endpoint.Targets{"1.2.3.4"},
   852  					RecordType: endpoint.RecordTypeA,
   853  				},
   854  			},
   855  		},
   856  		{
   857  			title:           "ingress rules with single tls having multiple hostnames",
   858  			targetNamespace: "",
   859  			ingressItems: []fakeIngress{
   860  				{
   861  					name:        "fake1",
   862  					namespace:   namespace,
   863  					tlsdnsnames: [][]string{{"example.org", "example2.org"}},
   864  					ips:         []string{"1.2.3.4"},
   865  				},
   866  			},
   867  			expected: []*endpoint.Endpoint{
   868  				{
   869  					DNSName:    "example.org",
   870  					Targets:    endpoint.Targets{"1.2.3.4"},
   871  					RecordType: endpoint.RecordTypeA,
   872  				},
   873  				{
   874  					DNSName:    "example2.org",
   875  					Targets:    endpoint.Targets{"1.2.3.4"},
   876  					RecordType: endpoint.RecordTypeA,
   877  				},
   878  			},
   879  		},
   880  		{
   881  			title:           "ingress rules with multiple tls having multiple hostnames",
   882  			targetNamespace: "",
   883  			ingressItems: []fakeIngress{
   884  				{
   885  					name:        "fake1",
   886  					namespace:   namespace,
   887  					tlsdnsnames: [][]string{{"example.org", "example2.org"}, {"example3.org", "example4.org"}},
   888  					ips:         []string{"1.2.3.4"},
   889  				},
   890  			},
   891  			expected: []*endpoint.Endpoint{
   892  				{
   893  					DNSName:    "example.org",
   894  					Targets:    endpoint.Targets{"1.2.3.4"},
   895  					RecordType: endpoint.RecordTypeA,
   896  				},
   897  				{
   898  					DNSName:    "example2.org",
   899  					Targets:    endpoint.Targets{"1.2.3.4"},
   900  					RecordType: endpoint.RecordTypeA,
   901  				},
   902  				{
   903  					DNSName:    "example3.org",
   904  					Targets:    endpoint.Targets{"1.2.3.4"},
   905  					RecordType: endpoint.RecordTypeA,
   906  				},
   907  				{
   908  					DNSName:    "example4.org",
   909  					Targets:    endpoint.Targets{"1.2.3.4"},
   910  					RecordType: endpoint.RecordTypeA,
   911  				},
   912  			},
   913  		},
   914  		{
   915  			title:           "ingress rules with hostname annotation",
   916  			targetNamespace: "",
   917  			ingressItems: []fakeIngress{
   918  				{
   919  					name:      "fake1",
   920  					namespace: namespace,
   921  					annotations: map[string]string{
   922  						hostnameAnnotationKey: "dns-through-hostname.com",
   923  					},
   924  					dnsnames: []string{"example.org"},
   925  					ips:      []string{"1.2.3.4"},
   926  				},
   927  			},
   928  			expected: []*endpoint.Endpoint{
   929  				{
   930  					DNSName:    "example.org",
   931  					Targets:    endpoint.Targets{"1.2.3.4"},
   932  					RecordType: endpoint.RecordTypeA,
   933  				},
   934  				{
   935  					DNSName:    "dns-through-hostname.com",
   936  					Targets:    endpoint.Targets{"1.2.3.4"},
   937  					RecordType: endpoint.RecordTypeA,
   938  				},
   939  			},
   940  		},
   941  		{
   942  			title:           "ingress rules with hostname annotation having multiple hostnames",
   943  			targetNamespace: "",
   944  			ingressItems: []fakeIngress{
   945  				{
   946  					name:      "fake1",
   947  					namespace: namespace,
   948  					annotations: map[string]string{
   949  						hostnameAnnotationKey: "dns-through-hostname.com, another-dns-through-hostname.com",
   950  					},
   951  					dnsnames: []string{"example.org"},
   952  					ips:      []string{"1.2.3.4"},
   953  				},
   954  			},
   955  			expected: []*endpoint.Endpoint{
   956  				{
   957  					DNSName:    "example.org",
   958  					Targets:    endpoint.Targets{"1.2.3.4"},
   959  					RecordType: endpoint.RecordTypeA,
   960  				},
   961  				{
   962  					DNSName:    "dns-through-hostname.com",
   963  					Targets:    endpoint.Targets{"1.2.3.4"},
   964  					RecordType: endpoint.RecordTypeA,
   965  				},
   966  				{
   967  					DNSName:    "another-dns-through-hostname.com",
   968  					Targets:    endpoint.Targets{"1.2.3.4"},
   969  					RecordType: endpoint.RecordTypeA,
   970  				},
   971  			},
   972  		},
   973  		{
   974  			title:           "ingress rules with hostname and target annotation",
   975  			targetNamespace: "",
   976  			ingressItems: []fakeIngress{
   977  				{
   978  					name:      "fake1",
   979  					namespace: namespace,
   980  					annotations: map[string]string{
   981  						hostnameAnnotationKey: "dns-through-hostname.com",
   982  						targetAnnotationKey:   "ingress-target.com",
   983  					},
   984  					dnsnames: []string{"example.org"},
   985  					ips:      []string{},
   986  				},
   987  			},
   988  			expected: []*endpoint.Endpoint{
   989  				{
   990  					DNSName:    "example.org",
   991  					Targets:    endpoint.Targets{"ingress-target.com"},
   992  					RecordType: endpoint.RecordTypeCNAME,
   993  				},
   994  				{
   995  					DNSName:    "dns-through-hostname.com",
   996  					Targets:    endpoint.Targets{"ingress-target.com"},
   997  					RecordType: endpoint.RecordTypeCNAME,
   998  				},
   999  			},
  1000  		},
  1001  		{
  1002  			title:           "ingress rules with annotation and custom TTL",
  1003  			targetNamespace: "",
  1004  			ingressItems: []fakeIngress{
  1005  				{
  1006  					name:      "fake1",
  1007  					namespace: namespace,
  1008  					annotations: map[string]string{
  1009  						targetAnnotationKey: "ingress-target.com",
  1010  						ttlAnnotationKey:    "6",
  1011  					},
  1012  					dnsnames: []string{"example.org"},
  1013  					ips:      []string{},
  1014  				},
  1015  				{
  1016  					name:      "fake2",
  1017  					namespace: namespace,
  1018  					annotations: map[string]string{
  1019  						targetAnnotationKey: "ingress-target.com",
  1020  						ttlAnnotationKey:    "1",
  1021  					},
  1022  					dnsnames: []string{"example2.org"},
  1023  					ips:      []string{"8.8.8.8"},
  1024  				},
  1025  				{
  1026  					name:      "fake3",
  1027  					namespace: namespace,
  1028  					annotations: map[string]string{
  1029  						targetAnnotationKey: "ingress-target.com",
  1030  						ttlAnnotationKey:    "10s",
  1031  					},
  1032  					dnsnames: []string{"example3.org"},
  1033  					ips:      []string{"8.8.4.4"},
  1034  				},
  1035  			},
  1036  			expected: []*endpoint.Endpoint{
  1037  				{
  1038  					DNSName:    "example.org",
  1039  					RecordType: endpoint.RecordTypeCNAME,
  1040  					Targets:    endpoint.Targets{"ingress-target.com"},
  1041  					RecordTTL:  endpoint.TTL(6),
  1042  				},
  1043  				{
  1044  					DNSName:    "example2.org",
  1045  					RecordType: endpoint.RecordTypeCNAME,
  1046  					Targets:    endpoint.Targets{"ingress-target.com"},
  1047  					RecordTTL:  endpoint.TTL(1),
  1048  				},
  1049  				{
  1050  					DNSName:    "example3.org",
  1051  					RecordType: endpoint.RecordTypeCNAME,
  1052  					Targets:    endpoint.Targets{"ingress-target.com"},
  1053  					RecordTTL:  endpoint.TTL(10),
  1054  				},
  1055  			},
  1056  		},
  1057  		{
  1058  			title:           "ingress rules with alias and target annotation",
  1059  			targetNamespace: "",
  1060  			ingressItems: []fakeIngress{
  1061  				{
  1062  					name:      "fake1",
  1063  					namespace: namespace,
  1064  					annotations: map[string]string{
  1065  						targetAnnotationKey: "ingress-target.com",
  1066  						aliasAnnotationKey:  "true",
  1067  					},
  1068  					dnsnames: []string{"example.org"},
  1069  					ips:      []string{},
  1070  				},
  1071  			},
  1072  			expected: []*endpoint.Endpoint{
  1073  				{
  1074  					DNSName:    "example.org",
  1075  					Targets:    endpoint.Targets{"ingress-target.com"},
  1076  					RecordType: endpoint.RecordTypeCNAME,
  1077  					ProviderSpecific: endpoint.ProviderSpecific{{
  1078  						Name: "alias", Value: "true",
  1079  					}},
  1080  				},
  1081  			},
  1082  		},
  1083  		{
  1084  			title:           "ingress rules with alias set false and target annotation",
  1085  			targetNamespace: "",
  1086  			ingressItems: []fakeIngress{
  1087  				{
  1088  					name:      "fake1",
  1089  					namespace: namespace,
  1090  					annotations: map[string]string{
  1091  						targetAnnotationKey: "ingress-target.com",
  1092  						aliasAnnotationKey:  "false",
  1093  					},
  1094  					dnsnames: []string{"example.org"},
  1095  					ips:      []string{},
  1096  				},
  1097  			},
  1098  			expected: []*endpoint.Endpoint{
  1099  				{
  1100  					DNSName:    "example.org",
  1101  					Targets:    endpoint.Targets{"ingress-target.com"},
  1102  					RecordType: endpoint.RecordTypeCNAME,
  1103  				},
  1104  			},
  1105  		},
  1106  		{
  1107  			title:           "template for ingress with annotation",
  1108  			targetNamespace: "",
  1109  			ingressItems: []fakeIngress{
  1110  				{
  1111  					name:      "fake1",
  1112  					namespace: namespace,
  1113  					annotations: map[string]string{
  1114  						targetAnnotationKey: "ingress-target.com",
  1115  					},
  1116  					dnsnames:  []string{},
  1117  					ips:       []string{},
  1118  					hostnames: []string{},
  1119  				},
  1120  				{
  1121  					name:      "fake2",
  1122  					namespace: namespace,
  1123  					annotations: map[string]string{
  1124  						targetAnnotationKey: "ingress-target.com",
  1125  					},
  1126  					dnsnames: []string{},
  1127  					ips:      []string{"8.8.8.8"},
  1128  				},
  1129  				{
  1130  					name:      "fake3",
  1131  					namespace: namespace,
  1132  					annotations: map[string]string{
  1133  						targetAnnotationKey: "1.2.3.4",
  1134  					},
  1135  					dnsnames:  []string{},
  1136  					ips:       []string{},
  1137  					hostnames: []string{},
  1138  				},
  1139  			},
  1140  			expected: []*endpoint.Endpoint{
  1141  				{
  1142  					DNSName:    "fake1.ext-dns.test.com",
  1143  					Targets:    endpoint.Targets{"ingress-target.com"},
  1144  					RecordType: endpoint.RecordTypeCNAME,
  1145  				},
  1146  				{
  1147  					DNSName:    "fake2.ext-dns.test.com",
  1148  					Targets:    endpoint.Targets{"ingress-target.com"},
  1149  					RecordType: endpoint.RecordTypeCNAME,
  1150  				},
  1151  				{
  1152  					DNSName:    "fake3.ext-dns.test.com",
  1153  					Targets:    endpoint.Targets{"1.2.3.4"},
  1154  					RecordType: endpoint.RecordTypeA,
  1155  				},
  1156  			},
  1157  			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
  1158  		},
  1159  		{
  1160  			title:           "Ingress with empty annotation",
  1161  			targetNamespace: "",
  1162  			ingressItems: []fakeIngress{
  1163  				{
  1164  					name:      "fake1",
  1165  					namespace: namespace,
  1166  					annotations: map[string]string{
  1167  						targetAnnotationKey: "",
  1168  					},
  1169  					dnsnames:  []string{},
  1170  					ips:       []string{},
  1171  					hostnames: []string{},
  1172  				},
  1173  			},
  1174  			expected:     []*endpoint.Endpoint{},
  1175  			fqdnTemplate: "{{.Name}}.ext-dns.test.com",
  1176  		},
  1177  		{
  1178  			title:                    "ignore hostname annotation",
  1179  			targetNamespace:          "",
  1180  			ignoreHostnameAnnotation: true,
  1181  			ingressItems: []fakeIngress{
  1182  				{
  1183  					name:      "fake1",
  1184  					namespace: namespace,
  1185  					dnsnames:  []string{"example.org"},
  1186  					ips:       []string{"8.8.8.8"},
  1187  				},
  1188  				{
  1189  					name:      "fake2",
  1190  					namespace: namespace,
  1191  					annotations: map[string]string{
  1192  						hostnameAnnotationKey: "dns-through-hostname.com",
  1193  					},
  1194  					dnsnames:  []string{"new.org"},
  1195  					hostnames: []string{"lb.com"},
  1196  				},
  1197  			},
  1198  			expected: []*endpoint.Endpoint{
  1199  				{
  1200  					DNSName:    "example.org",
  1201  					RecordType: endpoint.RecordTypeA,
  1202  					Targets:    endpoint.Targets{"8.8.8.8"},
  1203  				},
  1204  				{
  1205  					DNSName:    "new.org",
  1206  					RecordType: endpoint.RecordTypeCNAME,
  1207  					Targets:    endpoint.Targets{"lb.com"},
  1208  				},
  1209  			},
  1210  		},
  1211  		{
  1212  			title:                "ignore tls section",
  1213  			targetNamespace:      "",
  1214  			ignoreIngressTLSSpec: true,
  1215  			ingressItems: []fakeIngress{
  1216  				{
  1217  					name:        "fake1",
  1218  					namespace:   namespace,
  1219  					tlsdnsnames: [][]string{{"example.org"}},
  1220  					ips:         []string{"1.2.3.4"},
  1221  				},
  1222  			},
  1223  			expected: []*endpoint.Endpoint{},
  1224  		},
  1225  		{
  1226  			title:                "reading tls section",
  1227  			targetNamespace:      "",
  1228  			ignoreIngressTLSSpec: false,
  1229  			ingressItems: []fakeIngress{
  1230  				{
  1231  					name:        "fake1",
  1232  					namespace:   namespace,
  1233  					tlsdnsnames: [][]string{{"example.org"}},
  1234  					ips:         []string{"1.2.3.4"},
  1235  				},
  1236  			},
  1237  			expected: []*endpoint.Endpoint{
  1238  				{
  1239  					DNSName:    "example.org",
  1240  					RecordType: endpoint.RecordTypeA,
  1241  					Targets:    endpoint.Targets{"1.2.3.4"},
  1242  				},
  1243  			},
  1244  		},
  1245  		{
  1246  			title:             "ingressClassName filtering",
  1247  			targetNamespace:   "",
  1248  			ingressClassNames: []string{"public", "dmz"},
  1249  			ingressItems: []fakeIngress{
  1250  				{
  1251  					name:        "none",
  1252  					namespace:   namespace,
  1253  					tlsdnsnames: [][]string{{"none.example.org"}},
  1254  					ips:         []string{"1.0.0.0"},
  1255  				},
  1256  				{
  1257  					name:             "fake-public",
  1258  					namespace:        namespace,
  1259  					tlsdnsnames:      [][]string{{"example.org"}},
  1260  					ips:              []string{"1.2.3.4"},
  1261  					ingressClassName: "public", // match
  1262  				},
  1263  				{
  1264  					name:             "fake-internal",
  1265  					namespace:        namespace,
  1266  					tlsdnsnames:      [][]string{{"int.example.org"}},
  1267  					ips:              []string{"2.3.4.5"},
  1268  					ingressClassName: "internal",
  1269  				},
  1270  				{
  1271  					name:             "fake-dmz",
  1272  					namespace:        namespace,
  1273  					tlsdnsnames:      [][]string{{"dmz.example.org"}},
  1274  					ips:              []string{"3.4.5.6"},
  1275  					ingressClassName: "dmz", // match
  1276  				},
  1277  				{
  1278  					name:        "annotated-dmz",
  1279  					namespace:   namespace,
  1280  					tlsdnsnames: [][]string{{"annodmz.example.org"}},
  1281  					ips:         []string{"4.5.6.7"},
  1282  					annotations: map[string]string{
  1283  						"kubernetes.io/ingress.class": "dmz", // match
  1284  					},
  1285  				},
  1286  				{
  1287  					name:        "fake-internal-annotated-dmz",
  1288  					namespace:   namespace,
  1289  					tlsdnsnames: [][]string{{"int-annodmz.example.org"}},
  1290  					ips:         []string{"5.6.7.8"},
  1291  					annotations: map[string]string{
  1292  						"kubernetes.io/ingress.class": "dmz", // match but ignored (non-empty ingressClassName)
  1293  					},
  1294  					ingressClassName: "internal",
  1295  				},
  1296  				{
  1297  					name:        "fake-dmz-annotated-internal",
  1298  					namespace:   namespace,
  1299  					tlsdnsnames: [][]string{{"dmz-annoint.example.org"}},
  1300  					ips:         []string{"6.7.8.9"},
  1301  					annotations: map[string]string{
  1302  						"kubernetes.io/ingress.class": "internal",
  1303  					},
  1304  					ingressClassName: "dmz", // match
  1305  				},
  1306  				{
  1307  					name:        "empty-annotated-dmz",
  1308  					namespace:   namespace,
  1309  					tlsdnsnames: [][]string{{"empty-annotdmz.example.org"}},
  1310  					ips:         []string{"7.8.9.0"},
  1311  					annotations: map[string]string{
  1312  						"kubernetes.io/ingress.class": "dmz", // match (empty ingressClassName)
  1313  					},
  1314  					ingressClassName: "",
  1315  				},
  1316  				{
  1317  					name:        "empty-annotated-internal",
  1318  					namespace:   namespace,
  1319  					tlsdnsnames: [][]string{{"empty-annotint.example.org"}},
  1320  					ips:         []string{"8.9.0.1"},
  1321  					annotations: map[string]string{
  1322  						"kubernetes.io/ingress.class": "internal",
  1323  					},
  1324  					ingressClassName: "",
  1325  				},
  1326  			},
  1327  			expected: []*endpoint.Endpoint{
  1328  				{
  1329  					DNSName:    "example.org",
  1330  					RecordType: endpoint.RecordTypeA,
  1331  					Targets:    endpoint.Targets{"1.2.3.4"},
  1332  				},
  1333  				{
  1334  					DNSName:    "dmz.example.org",
  1335  					RecordType: endpoint.RecordTypeA,
  1336  					Targets:    endpoint.Targets{"3.4.5.6"},
  1337  				},
  1338  				{
  1339  					DNSName:    "annodmz.example.org",
  1340  					RecordType: endpoint.RecordTypeA,
  1341  					Targets:    endpoint.Targets{"4.5.6.7"},
  1342  				},
  1343  				{
  1344  					DNSName:    "dmz-annoint.example.org",
  1345  					RecordType: endpoint.RecordTypeA,
  1346  					Targets:    endpoint.Targets{"6.7.8.9"},
  1347  				},
  1348  				{
  1349  					DNSName:    "empty-annotdmz.example.org",
  1350  					RecordType: endpoint.RecordTypeA,
  1351  					Targets:    endpoint.Targets{"7.8.9.0"},
  1352  				},
  1353  			},
  1354  		},
  1355  		{
  1356  			ingressLabelSelector: labels.SelectorFromSet(labels.Set{"app": "web-external"}),
  1357  			title:                "ingress with matching labels",
  1358  			targetNamespace:      "",
  1359  			ingressItems: []fakeIngress{
  1360  				{
  1361  					name:      "fake1",
  1362  					namespace: namespace,
  1363  					dnsnames:  []string{"example.org"},
  1364  					ips:       []string{"8.8.8.8"},
  1365  					labels:    map[string]string{"app": "web-external", "name": "reverse-proxy"},
  1366  				},
  1367  			},
  1368  			expected: []*endpoint.Endpoint{
  1369  				{
  1370  					DNSName:    "example.org",
  1371  					RecordType: endpoint.RecordTypeA,
  1372  					Targets:    endpoint.Targets{"8.8.8.8"},
  1373  				},
  1374  			},
  1375  		},
  1376  		{
  1377  			ingressLabelSelector: labels.SelectorFromSet(labels.Set{"app": "web-external"}),
  1378  			title:                "ingress without matching labels",
  1379  			targetNamespace:      "",
  1380  			ingressItems: []fakeIngress{
  1381  				{
  1382  					name:      "fake1",
  1383  					namespace: namespace,
  1384  					dnsnames:  []string{"example.org"},
  1385  					ips:       []string{"8.8.8.8"},
  1386  					labels:    map[string]string{"app": "web-internal", "name": "reverse-proxy"},
  1387  				},
  1388  			},
  1389  			expected: []*endpoint.Endpoint{},
  1390  		},
  1391  	} {
  1392  		ti := ti
  1393  		t.Run(ti.title, func(t *testing.T) {
  1394  			t.Parallel()
  1395  
  1396  			fakeClient := fake.NewSimpleClientset()
  1397  			for _, item := range ti.ingressItems {
  1398  				ingress := item.Ingress()
  1399  				_, err := fakeClient.NetworkingV1().Ingresses(ingress.Namespace).Create(context.Background(), ingress, metav1.CreateOptions{})
  1400  				require.NoError(t, err)
  1401  			}
  1402  
  1403  			if ti.ingressLabelSelector == nil {
  1404  				ti.ingressLabelSelector = labels.Everything()
  1405  			}
  1406  
  1407  			source, _ := NewIngressSource(
  1408  				context.TODO(),
  1409  				fakeClient,
  1410  				ti.targetNamespace,
  1411  				ti.annotationFilter,
  1412  				ti.fqdnTemplate,
  1413  				ti.combineFQDNAndAnnotation,
  1414  				ti.ignoreHostnameAnnotation,
  1415  				ti.ignoreIngressTLSSpec,
  1416  				ti.ignoreIngressRulesSpec,
  1417  				ti.ingressLabelSelector,
  1418  				ti.ingressClassNames,
  1419  			)
  1420  			// Informer cache has all of the ingresses. Retrieve and validate their endpoints.
  1421  			res, err := source.Endpoints(context.Background())
  1422  			if ti.expectError {
  1423  				require.Error(t, err)
  1424  			} else {
  1425  				require.NoError(t, err)
  1426  			}
  1427  			validateEndpoints(t, res, ti.expected)
  1428  		})
  1429  	}
  1430  }
  1431  
  1432  // ingress specific helper functions
  1433  type fakeIngress struct {
  1434  	dnsnames         []string
  1435  	tlsdnsnames      [][]string
  1436  	ips              []string
  1437  	hostnames        []string
  1438  	namespace        string
  1439  	name             string
  1440  	annotations      map[string]string
  1441  	labels           map[string]string
  1442  	ingressClassName string
  1443  }
  1444  
  1445  func (ing fakeIngress) Ingress() *networkv1.Ingress {
  1446  	ingress := &networkv1.Ingress{
  1447  		ObjectMeta: metav1.ObjectMeta{
  1448  			Namespace:   ing.namespace,
  1449  			Name:        ing.name,
  1450  			Annotations: ing.annotations,
  1451  			Labels:      ing.labels,
  1452  		},
  1453  		Spec: networkv1.IngressSpec{
  1454  			Rules:            []networkv1.IngressRule{},
  1455  			IngressClassName: &ing.ingressClassName,
  1456  		},
  1457  		Status: networkv1.IngressStatus{
  1458  			LoadBalancer: networkv1.IngressLoadBalancerStatus{
  1459  				Ingress: []networkv1.IngressLoadBalancerIngress{},
  1460  			},
  1461  		},
  1462  	}
  1463  	for _, dnsname := range ing.dnsnames {
  1464  		ingress.Spec.Rules = append(ingress.Spec.Rules, networkv1.IngressRule{
  1465  			Host: dnsname,
  1466  		})
  1467  	}
  1468  	for _, hosts := range ing.tlsdnsnames {
  1469  		ingress.Spec.TLS = append(ingress.Spec.TLS, networkv1.IngressTLS{
  1470  			Hosts: hosts,
  1471  		})
  1472  	}
  1473  	for _, ip := range ing.ips {
  1474  		ingress.Status.LoadBalancer.Ingress = append(ingress.Status.LoadBalancer.Ingress, networkv1.IngressLoadBalancerIngress{
  1475  			IP: ip,
  1476  		})
  1477  	}
  1478  	for _, hostname := range ing.hostnames {
  1479  		ingress.Status.LoadBalancer.Ingress = append(ingress.Status.LoadBalancer.Ingress, networkv1.IngressLoadBalancerIngress{
  1480  			Hostname: hostname,
  1481  		})
  1482  	}
  1483  	return ingress
  1484  }