sigs.k8s.io/external-dns@v0.14.1/source/skipper_routegroup_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/pkg/errors"
    24  	"github.com/stretchr/testify/assert"
    25  	"sigs.k8s.io/external-dns/endpoint"
    26  )
    27  
    28  func createTestRouteGroup(ns, name string, annotations map[string]string, hosts []string, destinations []routeGroupLoadBalancer) *routeGroup {
    29  	return &routeGroup{
    30  		Metadata: itemMetadata{
    31  			Namespace:   ns,
    32  			Name:        name,
    33  			Annotations: annotations,
    34  		},
    35  		Spec: routeGroupSpec{
    36  			Hosts: hosts,
    37  		},
    38  		Status: routeGroupStatus{
    39  			LoadBalancer: routeGroupLoadBalancerStatus{
    40  				RouteGroup: destinations,
    41  			},
    42  		},
    43  	}
    44  }
    45  
    46  func TestEndpointsFromRouteGroups(t *testing.T) {
    47  	t.Parallel()
    48  
    49  	for _, tt := range []struct {
    50  		name   string
    51  		source *routeGroupSource
    52  		rg     *routeGroup
    53  		want   []*endpoint.Endpoint
    54  	}{
    55  		{
    56  			name:   "Empty routegroup should return empty endpoints",
    57  			source: &routeGroupSource{},
    58  			rg:     &routeGroup{},
    59  			want:   []*endpoint.Endpoint{},
    60  		},
    61  		{
    62  			name:   "Routegroup without hosts and destinations create no endpoints",
    63  			source: &routeGroupSource{},
    64  			rg:     createTestRouteGroup("namespace1", "rg1", nil, nil, nil),
    65  			want:   []*endpoint.Endpoint{},
    66  		},
    67  		{
    68  			name:   "Routegroup without hosts create no endpoints",
    69  			source: &routeGroupSource{},
    70  			rg: createTestRouteGroup("namespace1", "rg1", nil, nil, []routeGroupLoadBalancer{
    71  				{
    72  					Hostname: "lb.example.org",
    73  				},
    74  			}),
    75  			want: []*endpoint.Endpoint{},
    76  		},
    77  		{
    78  			name:   "Routegroup without destinations create no endpoints",
    79  			source: &routeGroupSource{},
    80  			rg:     createTestRouteGroup("namespace1", "rg1", nil, []string{"rg1.k8s.example"}, nil),
    81  			want:   []*endpoint.Endpoint{},
    82  		},
    83  		{
    84  			name:   "Routegroup with hosts and destinations creates an endpoint",
    85  			source: &routeGroupSource{},
    86  			rg: createTestRouteGroup("namespace1", "rg1", nil, []string{"rg1.k8s.example"}, []routeGroupLoadBalancer{
    87  				{
    88  					Hostname: "lb.example.org",
    89  				},
    90  			}),
    91  			want: []*endpoint.Endpoint{
    92  				{
    93  					DNSName:    "rg1.k8s.example",
    94  					RecordType: endpoint.RecordTypeCNAME,
    95  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
    96  				},
    97  			},
    98  		},
    99  		{
   100  			name:   "Routegroup with hostname annotation, creates endpoints from the annotation ",
   101  			source: &routeGroupSource{},
   102  			rg: createTestRouteGroup(
   103  				"namespace1",
   104  				"rg1",
   105  				map[string]string{
   106  					hostnameAnnotationKey: "my.example",
   107  				},
   108  				[]string{"rg1.k8s.example"},
   109  				[]routeGroupLoadBalancer{
   110  					{
   111  						Hostname: "lb.example.org",
   112  					},
   113  				},
   114  			),
   115  			want: []*endpoint.Endpoint{
   116  				{
   117  					DNSName:    "rg1.k8s.example",
   118  					RecordType: endpoint.RecordTypeCNAME,
   119  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   120  				},
   121  				{
   122  					DNSName:    "my.example",
   123  					RecordType: endpoint.RecordTypeCNAME,
   124  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   125  				},
   126  			},
   127  		},
   128  		{
   129  			name:   "Routegroup with hosts and destinations and ignoreHostnameAnnotation creates endpoints but ignores annotation",
   130  			source: &routeGroupSource{ignoreHostnameAnnotation: true},
   131  			rg: createTestRouteGroup(
   132  				"namespace1",
   133  				"rg1",
   134  				map[string]string{
   135  					hostnameAnnotationKey: "my.example",
   136  				},
   137  				[]string{"rg1.k8s.example"},
   138  				[]routeGroupLoadBalancer{
   139  					{
   140  						Hostname: "lb.example.org",
   141  					},
   142  				},
   143  			),
   144  			want: []*endpoint.Endpoint{
   145  				{
   146  					DNSName:    "rg1.k8s.example",
   147  					RecordType: endpoint.RecordTypeCNAME,
   148  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   149  				},
   150  			},
   151  		},
   152  		{
   153  			name:   "Routegroup with hosts and destinations and ttl creates an endpoint with ttl",
   154  			source: &routeGroupSource{ignoreHostnameAnnotation: true},
   155  			rg: createTestRouteGroup(
   156  				"namespace1",
   157  				"rg1",
   158  				map[string]string{
   159  					ttlAnnotationKey: "2189",
   160  				},
   161  				[]string{"rg1.k8s.example"},
   162  				[]routeGroupLoadBalancer{
   163  					{
   164  						Hostname: "lb.example.org",
   165  					},
   166  				},
   167  			),
   168  			want: []*endpoint.Endpoint{
   169  				{
   170  					DNSName:    "rg1.k8s.example",
   171  					RecordType: endpoint.RecordTypeCNAME,
   172  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   173  					RecordTTL:  endpoint.TTL(2189),
   174  				},
   175  			},
   176  		},
   177  		{
   178  			name:   "Routegroup with hosts and destination IP creates an endpoint",
   179  			source: &routeGroupSource{},
   180  			rg: createTestRouteGroup(
   181  				"namespace1",
   182  				"rg1",
   183  				nil,
   184  				[]string{"rg1.k8s.example"},
   185  				[]routeGroupLoadBalancer{
   186  					{
   187  						IP: "1.5.1.4",
   188  					},
   189  				},
   190  			),
   191  			want: []*endpoint.Endpoint{
   192  				{
   193  					DNSName:    "rg1.k8s.example",
   194  					RecordType: endpoint.RecordTypeA,
   195  					Targets:    endpoint.Targets([]string{"1.5.1.4"}),
   196  				},
   197  			},
   198  		},
   199  		{
   200  			name:   "Routegroup with hosts and mixed destinations creates endpoints",
   201  			source: &routeGroupSource{},
   202  			rg: createTestRouteGroup(
   203  				"namespace1",
   204  				"rg1",
   205  				nil,
   206  				[]string{"rg1.k8s.example"},
   207  				[]routeGroupLoadBalancer{
   208  					{
   209  						Hostname: "lb.example.org",
   210  						IP:       "1.5.1.4",
   211  					},
   212  				},
   213  			),
   214  			want: []*endpoint.Endpoint{
   215  				{
   216  					DNSName:    "rg1.k8s.example",
   217  					RecordType: endpoint.RecordTypeA,
   218  					Targets:    endpoint.Targets([]string{"1.5.1.4"}),
   219  				},
   220  				{
   221  					DNSName:    "rg1.k8s.example",
   222  					RecordType: endpoint.RecordTypeCNAME,
   223  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   224  				},
   225  			},
   226  		},
   227  	} {
   228  		t.Run(tt.name, func(t *testing.T) {
   229  			got := tt.source.endpointsFromRouteGroup(tt.rg)
   230  
   231  			validateEndpoints(t, got, tt.want)
   232  		})
   233  	}
   234  }
   235  
   236  type fakeRouteGroupClient struct {
   237  	returnErr bool
   238  	rg        *routeGroupList
   239  }
   240  
   241  func (f *fakeRouteGroupClient) getRouteGroupList(string) (*routeGroupList, error) {
   242  	if f.returnErr {
   243  		return nil, errors.New("Fake route group list error")
   244  	}
   245  	return f.rg, nil
   246  }
   247  
   248  func TestRouteGroupsEndpoints(t *testing.T) {
   249  	for _, tt := range []struct {
   250  		name         string
   251  		source       *routeGroupSource
   252  		fqdnTemplate string
   253  		want         []*endpoint.Endpoint
   254  		wantErr      bool
   255  	}{
   256  		{
   257  			name: "Empty routegroup should return empty endpoints",
   258  			source: &routeGroupSource{
   259  				cli: &fakeRouteGroupClient{
   260  					rg: &routeGroupList{},
   261  				},
   262  			},
   263  			want:    []*endpoint.Endpoint{},
   264  			wantErr: false,
   265  		},
   266  		{
   267  			name: "Single routegroup should return endpoints",
   268  			source: &routeGroupSource{
   269  				cli: &fakeRouteGroupClient{
   270  					rg: &routeGroupList{
   271  						Items: []*routeGroup{
   272  							createTestRouteGroup(
   273  								"namespace1",
   274  								"rg1",
   275  								nil,
   276  								[]string{"rg1.k8s.example"},
   277  								[]routeGroupLoadBalancer{
   278  									{
   279  										Hostname: "lb.example.org",
   280  									},
   281  								},
   282  							),
   283  						},
   284  					},
   285  				},
   286  			},
   287  			want: []*endpoint.Endpoint{
   288  				{
   289  					DNSName:    "rg1.k8s.example",
   290  					RecordType: endpoint.RecordTypeCNAME,
   291  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   292  				},
   293  			},
   294  		},
   295  		{
   296  			name:         "Single routegroup with combineFQDNAnnotation with fqdn template should return endpoints from fqdnTemplate and routegroup",
   297  			fqdnTemplate: "{{.Metadata.Name}}.{{.Metadata.Namespace}}.example",
   298  			source: &routeGroupSource{
   299  				combineFQDNAnnotation: true,
   300  				cli: &fakeRouteGroupClient{
   301  					rg: &routeGroupList{
   302  						Items: []*routeGroup{
   303  							createTestRouteGroup(
   304  								"namespace1",
   305  								"rg1",
   306  								nil,
   307  								[]string{"rg1.k8s.example"},
   308  								[]routeGroupLoadBalancer{
   309  									{
   310  										Hostname: "lb.example.org",
   311  									},
   312  								},
   313  							),
   314  						},
   315  					},
   316  				},
   317  			},
   318  			want: []*endpoint.Endpoint{
   319  				{
   320  					DNSName:    "rg1.k8s.example",
   321  					RecordType: endpoint.RecordTypeCNAME,
   322  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   323  				},
   324  				{
   325  					DNSName:    "rg1.namespace1.example",
   326  					RecordType: endpoint.RecordTypeCNAME,
   327  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   328  				},
   329  			},
   330  		},
   331  		{
   332  			name:         "Single routegroup without, with fqdn template should return endpoints from fqdnTemplate",
   333  			fqdnTemplate: "{{.Metadata.Name}}.{{.Metadata.Namespace}}.example",
   334  			source: &routeGroupSource{
   335  				cli: &fakeRouteGroupClient{
   336  					rg: &routeGroupList{
   337  						Items: []*routeGroup{
   338  							createTestRouteGroup(
   339  								"namespace1",
   340  								"rg1",
   341  								nil,
   342  								nil,
   343  								[]routeGroupLoadBalancer{
   344  									{
   345  										Hostname: "lb.example.org",
   346  									},
   347  								},
   348  							),
   349  						},
   350  					},
   351  				},
   352  			},
   353  			want: []*endpoint.Endpoint{
   354  				{
   355  					DNSName:    "rg1.namespace1.example",
   356  					RecordType: endpoint.RecordTypeCNAME,
   357  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   358  				},
   359  			},
   360  		},
   361  		{
   362  			name:         "Single routegroup without combineFQDNAnnotation with fqdn template should return endpoints not from fqdnTemplate",
   363  			fqdnTemplate: "{{.Metadata.Name}}.{{.Metadata.Namespace}}.example",
   364  			source: &routeGroupSource{
   365  				cli: &fakeRouteGroupClient{
   366  					rg: &routeGroupList{
   367  						Items: []*routeGroup{
   368  							createTestRouteGroup(
   369  								"namespace1",
   370  								"rg1",
   371  								nil,
   372  								[]string{"rg1.k8s.example"},
   373  								[]routeGroupLoadBalancer{
   374  									{
   375  										Hostname: "lb.example.org",
   376  									},
   377  								},
   378  							),
   379  						},
   380  					},
   381  				},
   382  			},
   383  			want: []*endpoint.Endpoint{
   384  				{
   385  					DNSName:    "rg1.k8s.example",
   386  					RecordType: endpoint.RecordTypeCNAME,
   387  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   388  				},
   389  			},
   390  		},
   391  		{
   392  			name: "Single routegroup with TTL should return endpoint with TTL",
   393  			source: &routeGroupSource{
   394  				cli: &fakeRouteGroupClient{
   395  					rg: &routeGroupList{
   396  						Items: []*routeGroup{
   397  							createTestRouteGroup(
   398  								"namespace1",
   399  								"rg1",
   400  								map[string]string{
   401  									ttlAnnotationKey: "2189",
   402  								},
   403  								[]string{"rg1.k8s.example"},
   404  								[]routeGroupLoadBalancer{
   405  									{
   406  										Hostname: "lb.example.org",
   407  									},
   408  								},
   409  							),
   410  						},
   411  					},
   412  				},
   413  			},
   414  			want: []*endpoint.Endpoint{
   415  				{
   416  					DNSName:    "rg1.k8s.example",
   417  					RecordType: endpoint.RecordTypeCNAME,
   418  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   419  					RecordTTL:  endpoint.TTL(2189),
   420  				},
   421  			},
   422  		},
   423  		{
   424  			name: "Routegroup with hosts and mixed destinations creates endpoints",
   425  			source: &routeGroupSource{
   426  				cli: &fakeRouteGroupClient{
   427  					rg: &routeGroupList{
   428  						Items: []*routeGroup{
   429  							createTestRouteGroup(
   430  								"namespace1",
   431  								"rg1",
   432  								nil,
   433  								[]string{"rg1.k8s.example"},
   434  								[]routeGroupLoadBalancer{
   435  									{
   436  										Hostname: "lb.example.org",
   437  										IP:       "1.5.1.4",
   438  									},
   439  								},
   440  							),
   441  						},
   442  					},
   443  				},
   444  			},
   445  			want: []*endpoint.Endpoint{
   446  				{
   447  					DNSName:    "rg1.k8s.example",
   448  					RecordType: endpoint.RecordTypeA,
   449  					Targets:    endpoint.Targets([]string{"1.5.1.4"}),
   450  				},
   451  				{
   452  					DNSName:    "rg1.k8s.example",
   453  					RecordType: endpoint.RecordTypeCNAME,
   454  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   455  				},
   456  			},
   457  		},
   458  		{
   459  			name: "multiple routegroups should return endpoints",
   460  			source: &routeGroupSource{
   461  				cli: &fakeRouteGroupClient{
   462  					rg: &routeGroupList{
   463  						Items: []*routeGroup{
   464  							createTestRouteGroup(
   465  								"namespace1",
   466  								"rg1",
   467  								nil,
   468  								[]string{"rg1.k8s.example"},
   469  								[]routeGroupLoadBalancer{
   470  									{
   471  										Hostname: "lb.example.org",
   472  									},
   473  								},
   474  							),
   475  							createTestRouteGroup(
   476  								"namespace1",
   477  								"rg2",
   478  								nil,
   479  								[]string{"rg2.k8s.example"},
   480  								[]routeGroupLoadBalancer{
   481  									{
   482  										Hostname: "lb.example.org",
   483  									},
   484  								},
   485  							),
   486  							createTestRouteGroup(
   487  								"namespace2",
   488  								"rg3",
   489  								nil,
   490  								[]string{"rg3.k8s.example"},
   491  								[]routeGroupLoadBalancer{
   492  									{
   493  										Hostname: "lb.example.org",
   494  									},
   495  								},
   496  							),
   497  							createTestRouteGroup(
   498  								"namespace3",
   499  								"rg",
   500  								nil,
   501  								[]string{"rg.k8s.example"},
   502  								[]routeGroupLoadBalancer{
   503  									{
   504  										Hostname: "lb2.example.org",
   505  									},
   506  								},
   507  							),
   508  						},
   509  					},
   510  				},
   511  			},
   512  			want: []*endpoint.Endpoint{
   513  				{
   514  					DNSName:    "rg1.k8s.example",
   515  					RecordType: endpoint.RecordTypeCNAME,
   516  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   517  				},
   518  				{
   519  					DNSName:    "rg2.k8s.example",
   520  					RecordType: endpoint.RecordTypeCNAME,
   521  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   522  				},
   523  				{
   524  					DNSName:    "rg3.k8s.example",
   525  					RecordType: endpoint.RecordTypeCNAME,
   526  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   527  				},
   528  				{
   529  					DNSName:    "rg.k8s.example",
   530  					RecordType: endpoint.RecordTypeCNAME,
   531  					Targets:    endpoint.Targets([]string{"lb2.example.org"}),
   532  				},
   533  			},
   534  		},
   535  		{
   536  			name: "multiple routegroups with filter annotations should return only filtered endpoints",
   537  			source: &routeGroupSource{
   538  				annotationFilter: "kubernetes.io/ingress.class=skipper",
   539  				cli: &fakeRouteGroupClient{
   540  					rg: &routeGroupList{
   541  						Items: []*routeGroup{
   542  							createTestRouteGroup(
   543  								"namespace1",
   544  								"rg1",
   545  								map[string]string{
   546  									"kubernetes.io/ingress.class": "skipper",
   547  								},
   548  								[]string{"rg1.k8s.example"},
   549  								[]routeGroupLoadBalancer{
   550  									{
   551  										Hostname: "lb.example.org",
   552  									},
   553  								},
   554  							),
   555  							createTestRouteGroup(
   556  								"namespace1",
   557  								"rg2",
   558  								map[string]string{
   559  									"kubernetes.io/ingress.class": "nginx",
   560  								},
   561  								[]string{"rg2.k8s.example"},
   562  								[]routeGroupLoadBalancer{
   563  									{
   564  										Hostname: "lb.example.org",
   565  									},
   566  								},
   567  							),
   568  							createTestRouteGroup(
   569  								"namespace2",
   570  								"rg3",
   571  								map[string]string{
   572  									"kubernetes.io/ingress.class": "",
   573  								},
   574  								[]string{"rg3.k8s.example"},
   575  								[]routeGroupLoadBalancer{
   576  									{
   577  										Hostname: "lb.example.org",
   578  									},
   579  								},
   580  							),
   581  							createTestRouteGroup(
   582  								"namespace3",
   583  								"rg",
   584  								nil,
   585  								[]string{"rg.k8s.example"},
   586  								[]routeGroupLoadBalancer{
   587  									{
   588  										Hostname: "lb2.example.org",
   589  									},
   590  								},
   591  							),
   592  						},
   593  					},
   594  				},
   595  			},
   596  			want: []*endpoint.Endpoint{
   597  				{
   598  					DNSName:    "rg1.k8s.example",
   599  					RecordType: endpoint.RecordTypeCNAME,
   600  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   601  				},
   602  			},
   603  		},
   604  		{
   605  			name: "multiple routegroups with set operation annotation filter should return only filtered endpoints",
   606  			source: &routeGroupSource{
   607  				annotationFilter: "kubernetes.io/ingress.class in (nginx, skipper)",
   608  				cli: &fakeRouteGroupClient{
   609  					rg: &routeGroupList{
   610  						Items: []*routeGroup{
   611  							createTestRouteGroup(
   612  								"namespace1",
   613  								"rg1",
   614  								map[string]string{
   615  									"kubernetes.io/ingress.class": "skipper",
   616  								},
   617  								[]string{"rg1.k8s.example"},
   618  								[]routeGroupLoadBalancer{
   619  									{
   620  										Hostname: "lb.example.org",
   621  									},
   622  								},
   623  							),
   624  							createTestRouteGroup(
   625  								"namespace1",
   626  								"rg2",
   627  								map[string]string{
   628  									"kubernetes.io/ingress.class": "nginx",
   629  								},
   630  								[]string{"rg2.k8s.example"},
   631  								[]routeGroupLoadBalancer{
   632  									{
   633  										Hostname: "lb.example.org",
   634  									},
   635  								},
   636  							),
   637  							createTestRouteGroup(
   638  								"namespace2",
   639  								"rg3",
   640  								map[string]string{
   641  									"kubernetes.io/ingress.class": "",
   642  								},
   643  								[]string{"rg3.k8s.example"},
   644  								[]routeGroupLoadBalancer{
   645  									{
   646  										Hostname: "lb.example.org",
   647  									},
   648  								},
   649  							),
   650  							createTestRouteGroup(
   651  								"namespace3",
   652  								"rg",
   653  								nil,
   654  								[]string{"rg.k8s.example"},
   655  								[]routeGroupLoadBalancer{
   656  									{
   657  										Hostname: "lb2.example.org",
   658  									},
   659  								},
   660  							),
   661  						},
   662  					},
   663  				},
   664  			},
   665  			want: []*endpoint.Endpoint{
   666  				{
   667  					DNSName:    "rg1.k8s.example",
   668  					RecordType: endpoint.RecordTypeCNAME,
   669  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   670  				},
   671  				{
   672  					DNSName:    "rg2.k8s.example",
   673  					RecordType: endpoint.RecordTypeCNAME,
   674  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   675  				},
   676  			},
   677  		},
   678  		{
   679  			name: "multiple routegroups with controller annotation filter should not return filtered endpoints",
   680  			source: &routeGroupSource{
   681  				cli: &fakeRouteGroupClient{
   682  					rg: &routeGroupList{
   683  						Items: []*routeGroup{
   684  							createTestRouteGroup(
   685  								"namespace1",
   686  								"rg1",
   687  								map[string]string{
   688  									controllerAnnotationKey: controllerAnnotationValue,
   689  								},
   690  								[]string{"rg1.k8s.example"},
   691  								[]routeGroupLoadBalancer{
   692  									{
   693  										Hostname: "lb.example.org",
   694  									},
   695  								},
   696  							),
   697  							createTestRouteGroup(
   698  								"namespace1",
   699  								"rg2",
   700  								map[string]string{
   701  									controllerAnnotationKey: "dns",
   702  								},
   703  								[]string{"rg2.k8s.example"},
   704  								[]routeGroupLoadBalancer{
   705  									{
   706  										Hostname: "lb.example.org",
   707  									},
   708  								},
   709  							),
   710  							createTestRouteGroup(
   711  								"namespace2",
   712  								"rg3",
   713  								nil,
   714  								[]string{"rg3.k8s.example"},
   715  								[]routeGroupLoadBalancer{
   716  									{
   717  										Hostname: "lb.example.org",
   718  									},
   719  								},
   720  							),
   721  						},
   722  					},
   723  				},
   724  			},
   725  			want: []*endpoint.Endpoint{
   726  				{
   727  					DNSName:    "rg1.k8s.example",
   728  					RecordType: endpoint.RecordTypeCNAME,
   729  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   730  				},
   731  				{
   732  					DNSName:    "rg3.k8s.example",
   733  					RecordType: endpoint.RecordTypeCNAME,
   734  					Targets:    endpoint.Targets([]string{"lb.example.org"}),
   735  				},
   736  			},
   737  		},
   738  	} {
   739  		t.Run(tt.name, func(t *testing.T) {
   740  			if tt.fqdnTemplate != "" {
   741  				tmpl, err := parseTemplate(tt.fqdnTemplate)
   742  				if err != nil {
   743  					t.Fatalf("Failed to parse template: %v", err)
   744  				}
   745  				tt.source.fqdnTemplate = tmpl
   746  			}
   747  
   748  			got, err := tt.source.Endpoints(context.Background())
   749  			if err != nil && !tt.wantErr {
   750  				t.Errorf("Got error, but does not want to get an error: %v", err)
   751  			}
   752  			if tt.wantErr && err == nil {
   753  				t.Fatal("Got no error, but we want to get an error")
   754  			}
   755  
   756  			validateEndpoints(t, got, tt.want)
   757  		})
   758  	}
   759  }
   760  
   761  func TestResourceLabelIsSet(t *testing.T) {
   762  	source := &routeGroupSource{
   763  		cli: &fakeRouteGroupClient{
   764  			rg: &routeGroupList{
   765  				Items: []*routeGroup{
   766  					createTestRouteGroup(
   767  						"namespace1",
   768  						"rg1",
   769  						nil,
   770  						[]string{"rg1.k8s.example"},
   771  						[]routeGroupLoadBalancer{
   772  							{
   773  								Hostname: "lb.example.org",
   774  							},
   775  						},
   776  					),
   777  				},
   778  			},
   779  		},
   780  	}
   781  
   782  	got, _ := source.Endpoints(context.Background())
   783  	for _, ep := range got {
   784  		if _, ok := ep.Labels[endpoint.ResourceLabelKey]; !ok {
   785  			t.Errorf("Failed to set resource label on ep %v", ep)
   786  		}
   787  	}
   788  }
   789  
   790  func TestDualstackLabelIsSet(t *testing.T) {
   791  	source := &routeGroupSource{
   792  		cli: &fakeRouteGroupClient{
   793  			rg: &routeGroupList{
   794  				Items: []*routeGroup{
   795  					createTestRouteGroup(
   796  						"namespace1",
   797  						"rg1",
   798  						map[string]string{
   799  							ALBDualstackAnnotationKey: ALBDualstackAnnotationValue,
   800  						},
   801  						[]string{"rg1.k8s.example"},
   802  						[]routeGroupLoadBalancer{
   803  							{
   804  								Hostname: "lb.example.org",
   805  							},
   806  						},
   807  					),
   808  				},
   809  			},
   810  		},
   811  	}
   812  
   813  	got, _ := source.Endpoints(context.Background())
   814  	for _, ep := range got {
   815  		if v, ok := ep.Labels[endpoint.DualstackLabelKey]; !ok || v != "true" {
   816  			t.Errorf("Failed to set resource label on ep %v", ep)
   817  		}
   818  	}
   819  }
   820  
   821  func TestParseTemplate(t *testing.T) {
   822  	for _, tt := range []struct {
   823  		name                     string
   824  		annotationFilter         string
   825  		fqdnTemplate             string
   826  		combineFQDNAndAnnotation bool
   827  		expectError              bool
   828  	}{
   829  		{
   830  			name:         "invalid template",
   831  			expectError:  true,
   832  			fqdnTemplate: "{{.Name",
   833  		},
   834  		{
   835  			name:        "valid empty template",
   836  			expectError: false,
   837  		},
   838  		{
   839  			name:         "valid template",
   840  			expectError:  false,
   841  			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
   842  		},
   843  		{
   844  			name:         "valid template",
   845  			expectError:  false,
   846  			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
   847  		},
   848  		{
   849  			name:                     "valid template",
   850  			expectError:              false,
   851  			fqdnTemplate:             "{{.Name}}-{{.Namespace}}.ext-dns.test.com, {{.Name}}-{{.Namespace}}.ext-dna.test.com",
   852  			combineFQDNAndAnnotation: true,
   853  		},
   854  		{
   855  			name:             "non-empty annotation filter label",
   856  			expectError:      false,
   857  			annotationFilter: "kubernetes.io/ingress.class=nginx",
   858  		},
   859  	} {
   860  		t.Run(tt.name, func(t *testing.T) {
   861  			_, err := parseTemplate(tt.fqdnTemplate)
   862  			if tt.expectError {
   863  				assert.Error(t, err)
   864  			} else {
   865  				assert.NoError(t, err)
   866  			}
   867  		})
   868  	}
   869  }