github.phpd.cn/cilium/cilium@v1.6.12/pkg/k8s/service_test.go (about)

     1  // Copyright 2018-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build !privileged_tests
    16  
    17  package k8s
    18  
    19  import (
    20  	"net"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/cilium/cilium/pkg/checker"
    25  	"github.com/cilium/cilium/pkg/k8s/types"
    26  	"github.com/cilium/cilium/pkg/loadbalancer"
    27  	"github.com/cilium/cilium/pkg/service"
    28  
    29  	"gopkg.in/check.v1"
    30  	"k8s.io/api/core/v1"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  )
    33  
    34  func (s *K8sSuite) TestGetAnnotationIncludeExternal(c *check.C) {
    35  	svc := &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    36  		Name: "foo",
    37  	}}}
    38  	c.Assert(getAnnotationIncludeExternal(svc), check.Equals, false)
    39  
    40  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    41  		Annotations: map[string]string{"io.cilium/global-service": "True"},
    42  	}}}
    43  	c.Assert(getAnnotationIncludeExternal(svc), check.Equals, true)
    44  
    45  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    46  		Annotations: map[string]string{"io.cilium/global-service": "false"},
    47  	}}}
    48  	c.Assert(getAnnotationIncludeExternal(svc), check.Equals, false)
    49  
    50  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    51  		Annotations: map[string]string{"io.cilium/global-service": ""},
    52  	}}}
    53  	c.Assert(getAnnotationIncludeExternal(svc), check.Equals, false)
    54  }
    55  
    56  func (s *K8sSuite) TestGetAnnotationShared(c *check.C) {
    57  	svc := &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    58  		Name: "foo",
    59  	}}}
    60  	c.Assert(getAnnotationShared(svc), check.Equals, false)
    61  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    62  		Annotations: map[string]string{"io.cilium/global-service": "true"},
    63  	}}}
    64  	c.Assert(getAnnotationShared(svc), check.Equals, true)
    65  
    66  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    67  		Annotations: map[string]string{"io.cilium/shared-service": "True"},
    68  	}}}
    69  	c.Assert(getAnnotationShared(svc), check.Equals, true)
    70  
    71  	svc = &types.Service{Service: &v1.Service{ObjectMeta: metav1.ObjectMeta{
    72  		Annotations: map[string]string{"io.cilium/global-service": "true", "io.cilium/shared-service": "false"},
    73  	}}}
    74  	c.Assert(getAnnotationShared(svc), check.Equals, false)
    75  }
    76  
    77  func (s *K8sSuite) TestParseServiceID(c *check.C) {
    78  	svc := &types.Service{
    79  		Service: &v1.Service{
    80  			ObjectMeta: metav1.ObjectMeta{
    81  				Name:      "foo",
    82  				Namespace: "bar",
    83  			},
    84  		},
    85  	}
    86  
    87  	c.Assert(ParseServiceID(svc), checker.DeepEquals, ServiceID{Namespace: "bar", Name: "foo"})
    88  }
    89  
    90  func (s *K8sSuite) TestParseService(c *check.C) {
    91  	k8sSvc := &types.Service{
    92  		Service: &v1.Service{
    93  			ObjectMeta: metav1.ObjectMeta{
    94  				Name:      "foo",
    95  				Namespace: "bar",
    96  				Labels: map[string]string{
    97  					"foo": "bar",
    98  				},
    99  			},
   100  			Spec: v1.ServiceSpec{
   101  				ClusterIP: "127.0.0.1",
   102  				Selector: map[string]string{
   103  					"foo": "bar",
   104  				},
   105  				Type: v1.ServiceTypeClusterIP,
   106  			},
   107  		},
   108  	}
   109  
   110  	id, svc := ParseService(k8sSvc)
   111  	c.Assert(id, checker.DeepEquals, ServiceID{Namespace: "bar", Name: "foo"})
   112  	c.Assert(svc, checker.DeepEquals, &Service{
   113  		FrontendIP: net.ParseIP("127.0.0.1"),
   114  		Selector:   map[string]string{"foo": "bar"},
   115  		Labels:     map[string]string{"foo": "bar"},
   116  		Ports:      map[loadbalancer.FEPortName]*loadbalancer.FEPort{},
   117  		NodePorts:  map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{},
   118  	})
   119  
   120  	k8sSvc = &types.Service{
   121  		Service: &v1.Service{
   122  			ObjectMeta: metav1.ObjectMeta{
   123  				Name:      "foo",
   124  				Namespace: "bar",
   125  				Labels: map[string]string{
   126  					"foo": "bar",
   127  				},
   128  			},
   129  			Spec: v1.ServiceSpec{
   130  				ClusterIP: "none",
   131  				Type:      v1.ServiceTypeClusterIP,
   132  			},
   133  		},
   134  	}
   135  
   136  	id, svc = ParseService(k8sSvc)
   137  	c.Assert(id, checker.DeepEquals, ServiceID{Namespace: "bar", Name: "foo"})
   138  	c.Assert(svc, checker.DeepEquals, &Service{
   139  		IsHeadless: true,
   140  		Labels:     map[string]string{"foo": "bar"},
   141  		Ports:      map[loadbalancer.FEPortName]*loadbalancer.FEPort{},
   142  		NodePorts:  map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{},
   143  	})
   144  }
   145  
   146  func (s *K8sSuite) TestIsK8ServiceExternal(c *check.C) {
   147  	si := Service{}
   148  
   149  	c.Assert(si.IsExternal(), check.Equals, true)
   150  
   151  	si.Selector = map[string]string{"l": "v"}
   152  	c.Assert(si.IsExternal(), check.Equals, false)
   153  }
   154  
   155  func (s *K8sSuite) TestServiceUniquePorts(c *check.C) {
   156  	type testMatrix struct {
   157  		input    Service
   158  		expected map[uint16]bool
   159  	}
   160  
   161  	matrix := []testMatrix{
   162  		{
   163  			input:    Service{},
   164  			expected: map[uint16]bool{},
   165  		},
   166  		{
   167  			input: Service{
   168  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   169  					loadbalancer.FEPortName("foo"): {
   170  						L4Addr: &loadbalancer.L4Addr{
   171  							Protocol: loadbalancer.NONE,
   172  							Port:     1,
   173  						},
   174  					},
   175  					loadbalancer.FEPortName("bar"): {
   176  						L4Addr: &loadbalancer.L4Addr{
   177  							Protocol: loadbalancer.NONE,
   178  							Port:     2,
   179  						},
   180  					},
   181  				},
   182  			},
   183  			expected: map[uint16]bool{
   184  				1: true,
   185  				2: true,
   186  			}},
   187  	}
   188  
   189  	for _, m := range matrix {
   190  		c.Assert(m.input.UniquePorts(), checker.DeepEquals, m.expected)
   191  	}
   192  }
   193  
   194  func TestService_Equals(t *testing.T) {
   195  	type args struct {
   196  		o *Service
   197  	}
   198  	tests := []struct {
   199  		name   string
   200  		fields *Service
   201  		args   args
   202  		want   bool
   203  	}{
   204  		{
   205  			name: "both equal",
   206  			fields: &Service{
   207  				FrontendIP: net.ParseIP("1.1.1.1"),
   208  				IsHeadless: true,
   209  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   210  					loadbalancer.FEPortName("foo"): {
   211  						L4Addr: &loadbalancer.L4Addr{
   212  							Protocol: loadbalancer.NONE,
   213  							Port:     1,
   214  						},
   215  						ID: 1,
   216  					},
   217  				},
   218  				NodePorts: map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{
   219  					loadbalancer.FEPortName("foo"): {
   220  						"0.0.0.0:31000": {
   221  							L3n4Addr: loadbalancer.L3n4Addr{
   222  								L4Addr: loadbalancer.L4Addr{
   223  									Protocol: loadbalancer.NONE,
   224  									Port:     31000,
   225  								},
   226  								IP: net.IPv4(0, 0, 0, 0),
   227  							},
   228  							ID: 1,
   229  						},
   230  					},
   231  				},
   232  
   233  				Labels: map[string]string{
   234  					"foo": "bar",
   235  				},
   236  				Selector: map[string]string{
   237  					"baz": "foz",
   238  				},
   239  			},
   240  			args: args{
   241  				o: &Service{
   242  					FrontendIP: net.ParseIP("1.1.1.1"),
   243  					IsHeadless: true,
   244  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   245  						loadbalancer.FEPortName("foo"): {
   246  							L4Addr: &loadbalancer.L4Addr{
   247  								Protocol: loadbalancer.NONE,
   248  								Port:     1,
   249  							},
   250  							ID: 1,
   251  						},
   252  					},
   253  					NodePorts: map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{
   254  						loadbalancer.FEPortName("foo"): {
   255  							"0.0.0.0:31000": {
   256  								L3n4Addr: loadbalancer.L3n4Addr{
   257  									L4Addr: loadbalancer.L4Addr{
   258  										Protocol: loadbalancer.NONE,
   259  										Port:     31000,
   260  									},
   261  									IP: net.IPv4(0, 0, 0, 0),
   262  								},
   263  								ID: 1,
   264  							},
   265  						},
   266  					},
   267  
   268  					Labels: map[string]string{
   269  						"foo": "bar",
   270  					},
   271  					Selector: map[string]string{
   272  						"baz": "foz",
   273  					},
   274  				},
   275  			},
   276  			want: true,
   277  		},
   278  		{
   279  			name: "different labels",
   280  			fields: &Service{
   281  				FrontendIP: net.ParseIP("1.1.1.1"),
   282  				IsHeadless: true,
   283  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   284  					loadbalancer.FEPortName("foo"): {
   285  						L4Addr: &loadbalancer.L4Addr{
   286  							Protocol: loadbalancer.NONE,
   287  							Port:     1,
   288  						},
   289  						ID: 1,
   290  					},
   291  				},
   292  				Labels: map[string]string{},
   293  				Selector: map[string]string{
   294  					"baz": "foz",
   295  				},
   296  			},
   297  			args: args{
   298  				o: &Service{
   299  					FrontendIP: net.ParseIP("1.1.1.1"),
   300  					IsHeadless: true,
   301  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   302  						loadbalancer.FEPortName("foo"): {
   303  							L4Addr: &loadbalancer.L4Addr{
   304  								Protocol: loadbalancer.NONE,
   305  								Port:     1,
   306  							},
   307  							ID: 1,
   308  						},
   309  					},
   310  					Labels: map[string]string{
   311  						"foo": "bar",
   312  					},
   313  					Selector: map[string]string{
   314  						"baz": "foz",
   315  					},
   316  				},
   317  			},
   318  			want: false,
   319  		},
   320  		{
   321  			name: "different selector",
   322  			fields: &Service{
   323  				FrontendIP: net.ParseIP("1.1.1.1"),
   324  				IsHeadless: true,
   325  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   326  					loadbalancer.FEPortName("foo"): {
   327  						L4Addr: &loadbalancer.L4Addr{
   328  							Protocol: loadbalancer.NONE,
   329  							Port:     1,
   330  						},
   331  						ID: 1,
   332  					},
   333  				},
   334  				Labels:   map[string]string{},
   335  				Selector: map[string]string{},
   336  			},
   337  			args: args{
   338  				o: &Service{
   339  					FrontendIP: net.ParseIP("1.1.1.1"),
   340  					IsHeadless: true,
   341  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   342  						loadbalancer.FEPortName("foo"): {
   343  							L4Addr: &loadbalancer.L4Addr{
   344  								Protocol: loadbalancer.NONE,
   345  								Port:     1,
   346  							},
   347  							ID: 1,
   348  						},
   349  					},
   350  					Labels: map[string]string{},
   351  					Selector: map[string]string{
   352  						"baz": "foz",
   353  					},
   354  				},
   355  			},
   356  			want: false,
   357  		},
   358  		{
   359  			name: "ports different name",
   360  			fields: &Service{
   361  				FrontendIP: net.ParseIP("1.1.1.1"),
   362  				IsHeadless: true,
   363  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   364  					loadbalancer.FEPortName("foz"): {
   365  						L4Addr: &loadbalancer.L4Addr{
   366  							Protocol: loadbalancer.NONE,
   367  							Port:     1,
   368  						},
   369  						ID: 1,
   370  					},
   371  				},
   372  				Labels:   map[string]string{},
   373  				Selector: map[string]string{},
   374  			},
   375  			args: args{
   376  				o: &Service{
   377  					FrontendIP: net.ParseIP("1.1.1.1"),
   378  					IsHeadless: true,
   379  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   380  						loadbalancer.FEPortName("foo"): {
   381  							L4Addr: &loadbalancer.L4Addr{
   382  								Protocol: loadbalancer.NONE,
   383  								Port:     1,
   384  							},
   385  							ID: 1,
   386  						},
   387  					},
   388  					Labels:   map[string]string{},
   389  					Selector: map[string]string{},
   390  				},
   391  			},
   392  			want: false,
   393  		},
   394  		{
   395  			name: "ports different content",
   396  			fields: &Service{
   397  				FrontendIP: net.ParseIP("1.1.1.1"),
   398  				IsHeadless: true,
   399  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   400  					loadbalancer.FEPortName("foo"): {
   401  						L4Addr: &loadbalancer.L4Addr{
   402  							Protocol: loadbalancer.NONE,
   403  							Port:     1,
   404  						},
   405  						ID: 1,
   406  					},
   407  				},
   408  				Labels:   map[string]string{},
   409  				Selector: map[string]string{},
   410  			},
   411  			args: args{
   412  				o: &Service{
   413  					FrontendIP: net.ParseIP("1.1.1.1"),
   414  					IsHeadless: true,
   415  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   416  						loadbalancer.FEPortName("foo"): {
   417  							L4Addr: &loadbalancer.L4Addr{
   418  								Protocol: loadbalancer.NONE,
   419  								Port:     2,
   420  							},
   421  							ID: 1,
   422  						},
   423  					},
   424  					Labels:   map[string]string{},
   425  					Selector: map[string]string{},
   426  				},
   427  			},
   428  			want: false,
   429  		},
   430  		{
   431  			name: "ports different one is bigger",
   432  			fields: &Service{
   433  				FrontendIP: net.ParseIP("1.1.1.1"),
   434  				IsHeadless: true,
   435  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   436  					loadbalancer.FEPortName("foo"): {
   437  						L4Addr: &loadbalancer.L4Addr{
   438  							Protocol: loadbalancer.NONE,
   439  							Port:     1,
   440  						},
   441  						ID: 1,
   442  					},
   443  				},
   444  				Labels:   map[string]string{},
   445  				Selector: map[string]string{},
   446  			},
   447  			args: args{
   448  				o: &Service{
   449  					FrontendIP: net.ParseIP("1.1.1.1"),
   450  					IsHeadless: true,
   451  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   452  						loadbalancer.FEPortName("foo"): {
   453  							L4Addr: &loadbalancer.L4Addr{
   454  								Protocol: loadbalancer.NONE,
   455  								Port:     1,
   456  							},
   457  							ID: 1,
   458  						},
   459  						loadbalancer.FEPortName("baz"): {
   460  							L4Addr: &loadbalancer.L4Addr{
   461  								Protocol: loadbalancer.NONE,
   462  								Port:     2,
   463  							},
   464  							ID: 2,
   465  						},
   466  					},
   467  					Labels:   map[string]string{},
   468  					Selector: map[string]string{},
   469  				},
   470  			},
   471  			want: false,
   472  		},
   473  		{
   474  			name: "ports different one is nil",
   475  			fields: &Service{
   476  				FrontendIP: net.ParseIP("1.1.1.1"),
   477  				IsHeadless: true,
   478  				Labels:     map[string]string{},
   479  				Selector:   map[string]string{},
   480  			},
   481  			args: args{
   482  				o: &Service{
   483  					FrontendIP: net.ParseIP("1.1.1.1"),
   484  					IsHeadless: true,
   485  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   486  						loadbalancer.FEPortName("foo"): {
   487  							L4Addr: &loadbalancer.L4Addr{
   488  								Protocol: loadbalancer.NONE,
   489  								Port:     1,
   490  							},
   491  							ID: 1,
   492  						},
   493  					},
   494  					Labels:   map[string]string{},
   495  					Selector: map[string]string{},
   496  				},
   497  			},
   498  			want: false,
   499  		},
   500  		{
   501  			name: "nodeports different",
   502  			fields: &Service{
   503  				FrontendIP: net.ParseIP("1.1.1.1"),
   504  				IsHeadless: true,
   505  				Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   506  					loadbalancer.FEPortName("foo"): {
   507  						L4Addr: &loadbalancer.L4Addr{
   508  							Protocol: loadbalancer.NONE,
   509  							Port:     1,
   510  						},
   511  						ID: 1,
   512  					},
   513  				},
   514  				NodePorts: map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{
   515  					loadbalancer.FEPortName("foo"): {
   516  						"1.1.1.1:31000": {
   517  							L3n4Addr: loadbalancer.L3n4Addr{
   518  								L4Addr: loadbalancer.L4Addr{
   519  									Protocol: loadbalancer.NONE,
   520  									Port:     31000,
   521  								},
   522  								IP: net.IPv4(1, 1, 1, 1),
   523  							},
   524  							ID: 1,
   525  						},
   526  					},
   527  				},
   528  
   529  				Labels: map[string]string{
   530  					"foo": "bar",
   531  				},
   532  				Selector: map[string]string{
   533  					"baz": "foz",
   534  				},
   535  			},
   536  			args: args{
   537  				o: &Service{
   538  					FrontendIP: net.ParseIP("1.1.1.1"),
   539  					IsHeadless: true,
   540  					Ports: map[loadbalancer.FEPortName]*loadbalancer.FEPort{
   541  						loadbalancer.FEPortName("foo"): {
   542  							L4Addr: &loadbalancer.L4Addr{
   543  								Protocol: loadbalancer.NONE,
   544  								Port:     1,
   545  							},
   546  							ID: 1,
   547  						},
   548  					},
   549  					NodePorts: map[loadbalancer.FEPortName]map[string]*loadbalancer.L3n4AddrID{
   550  						loadbalancer.FEPortName("foo"): {
   551  							"0.0.0.0:31000": {
   552  								L3n4Addr: loadbalancer.L3n4Addr{
   553  									L4Addr: loadbalancer.L4Addr{
   554  										Protocol: loadbalancer.NONE,
   555  										Port:     31000,
   556  									},
   557  									IP: net.IPv4(0, 0, 0, 0),
   558  								},
   559  								ID: 1,
   560  							},
   561  						},
   562  					},
   563  
   564  					Labels: map[string]string{
   565  						"foo": "bar",
   566  					},
   567  					Selector: map[string]string{
   568  						"baz": "foz",
   569  					},
   570  				},
   571  			},
   572  			want: false,
   573  		},
   574  		{
   575  			name: "both nil",
   576  			args: args{},
   577  			want: true,
   578  		},
   579  	}
   580  	for _, tt := range tests {
   581  		t.Run(tt.name, func(t *testing.T) {
   582  			si := tt.fields
   583  			if got := si.DeepEquals(tt.args.o); got != tt.want {
   584  				t.Errorf("Service.Equals() = %v, want %v", got, tt.want)
   585  			}
   586  		})
   587  	}
   588  }
   589  
   590  func (s *K8sSuite) TestServiceString(c *check.C) {
   591  	k8sSvc := &types.Service{
   592  		Service: &v1.Service{
   593  			ObjectMeta: metav1.ObjectMeta{
   594  				Name:      "foo",
   595  				Namespace: "bar",
   596  				Labels: map[string]string{
   597  					"foo": "bar",
   598  				},
   599  			},
   600  			Spec: v1.ServiceSpec{
   601  				ClusterIP: "127.0.0.1",
   602  				Selector: map[string]string{
   603  					"foo": "bar",
   604  				},
   605  				Type: v1.ServiceTypeClusterIP,
   606  			},
   607  		},
   608  	}
   609  
   610  	_, svc := ParseService(k8sSvc)
   611  	c.Assert(svc.String(), check.Equals, "frontend:127.0.0.1/ports=[]/selector=map[foo:bar]")
   612  }
   613  
   614  func (s *K8sSuite) TestNewClusterService(c *check.C) {
   615  	id, svc := ParseService(&types.Service{
   616  		Service: &v1.Service{
   617  			ObjectMeta: metav1.ObjectMeta{
   618  				Name:      "foo",
   619  				Namespace: "bar",
   620  				Labels: map[string]string{
   621  					"foo": "bar",
   622  				},
   623  			},
   624  			Spec: v1.ServiceSpec{
   625  				ClusterIP: "127.0.0.1",
   626  				Selector: map[string]string{
   627  					"foo": "bar",
   628  				},
   629  				Type: v1.ServiceTypeClusterIP,
   630  			},
   631  		},
   632  	})
   633  
   634  	_, endpoints := ParseEndpoints(&types.Endpoints{
   635  		Endpoints: &v1.Endpoints{
   636  			ObjectMeta: metav1.ObjectMeta{
   637  				Name:      "foo",
   638  				Namespace: "bar",
   639  			},
   640  			Subsets: []v1.EndpointSubset{
   641  				{
   642  					Addresses: []v1.EndpointAddress{{IP: "2.2.2.2"}},
   643  					Ports: []v1.EndpointPort{
   644  						{
   645  							Name:     "http-test-svc",
   646  							Port:     8080,
   647  							Protocol: v1.ProtocolTCP,
   648  						},
   649  					},
   650  				},
   651  			},
   652  		},
   653  	})
   654  
   655  	clusterService := NewClusterService(id, svc, endpoints)
   656  	c.Assert(clusterService, check.DeepEquals, service.ClusterService{
   657  		Name:      "foo",
   658  		Namespace: "bar",
   659  		Labels:    map[string]string{"foo": "bar"},
   660  		Selector:  map[string]string{"foo": "bar"},
   661  		Frontends: map[string]service.PortConfiguration{
   662  			"127.0.0.1": {},
   663  		},
   664  		Backends: map[string]service.PortConfiguration{
   665  			"2.2.2.2": {
   666  				"http-test-svc": {Protocol: loadbalancer.TCP, Port: 8080},
   667  			},
   668  		},
   669  	})
   670  }
   671  
   672  func TestParseServiceIDFrom(t *testing.T) {
   673  	type args struct {
   674  		dn string
   675  	}
   676  	tests := []struct {
   677  		args args
   678  		want *ServiceID
   679  	}{
   680  		{args: args{dn: "cilium-etcd-client.kube-system.svc"}, want: &ServiceID{Name: "cilium-etcd-client", Namespace: "kube-system"}},
   681  		{args: args{dn: "1.kube-system"}, want: &ServiceID{Name: "1", Namespace: "kube-system"}},
   682  		{args: args{dn: ".kube-system"}, want: &ServiceID{Name: "", Namespace: "kube-system"}},
   683  		{args: args{dn: "..kube-system"}, want: &ServiceID{Name: "", Namespace: ""}},
   684  		{args: args{dn: "2-..kube-system"}, want: &ServiceID{Name: "2-", Namespace: ""}},
   685  		{args: args{dn: ""}, want: nil},
   686  		{args: args{dn: "cilium-etcd-client.kube-system"}, want: &ServiceID{Name: "cilium-etcd-client", Namespace: "kube-system"}},
   687  		{args: args{dn: "cilium-etcd-client"}, want: nil},
   688  	}
   689  	for _, tt := range tests {
   690  		t.Run(tt.args.dn, func(t *testing.T) {
   691  			if got := ParseServiceIDFrom(tt.args.dn); !reflect.DeepEqual(got, tt.want) {
   692  				t.Errorf("ParseServiceIDFrom() = %v, want %v", got, tt.want)
   693  			}
   694  		})
   695  	}
   696  }