github.com/cilium/cilium@v1.16.2/pkg/hubble/peer/service_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package peer
     5  
     6  import (
     7  	"net"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/google/go-cmp/cmp"
    13  	"github.com/stretchr/testify/assert"
    14  
    15  	peerpb "github.com/cilium/cilium/api/v1/peer"
    16  	datapath "github.com/cilium/cilium/pkg/datapath/types"
    17  	"github.com/cilium/cilium/pkg/hubble/peer/serviceoption"
    18  	"github.com/cilium/cilium/pkg/hubble/testutils"
    19  	"github.com/cilium/cilium/pkg/lock"
    20  	"github.com/cilium/cilium/pkg/node/addressing"
    21  	"github.com/cilium/cilium/pkg/node/manager"
    22  	"github.com/cilium/cilium/pkg/node/types"
    23  )
    24  
    25  func TestService_Notify(t *testing.T) {
    26  	type args struct {
    27  		init   []types.Node
    28  		add    []types.Node
    29  		update []types.Node
    30  		del    []types.Node
    31  	}
    32  	tests := []struct {
    33  		name       string
    34  		svcOptions []serviceoption.Option
    35  		args       args
    36  		want       []*peerpb.ChangeNotification
    37  	}{
    38  		{
    39  			name:       "add 4 nodes with TLS info disabled",
    40  			svcOptions: []serviceoption.Option{serviceoption.WithoutTLSInfo()},
    41  			args: args{
    42  				init: []types.Node{
    43  					{
    44  						Name: "zero",
    45  						IPAddresses: []types.Address{
    46  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
    47  						},
    48  					},
    49  				},
    50  				add: []types.Node{
    51  					{
    52  						Name: "one",
    53  						IPAddresses: []types.Address{
    54  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
    55  						},
    56  					}, {
    57  						Name: "two",
    58  						IPAddresses: []types.Address{
    59  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
    60  						},
    61  					}, {
    62  						Name:    "one",
    63  						Cluster: "test",
    64  						IPAddresses: []types.Address{
    65  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
    66  						},
    67  					}, {
    68  						Name:    "two",
    69  						Cluster: "test",
    70  						IPAddresses: []types.Address{
    71  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
    72  						},
    73  					},
    74  				},
    75  			},
    76  			want: []*peerpb.ChangeNotification{
    77  				{
    78  					Name:    "zero",
    79  					Address: "192.0.1.1",
    80  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
    81  				}, {
    82  					Name:    "one",
    83  					Address: "192.0.2.1",
    84  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
    85  				}, {
    86  					Name:    "two",
    87  					Address: "2001:db8::68",
    88  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
    89  				}, {
    90  					Name:    "test/one",
    91  					Address: "10.0.10.5",
    92  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
    93  				}, {
    94  					Name:    "test/two",
    95  					Address: "10.0.10.6",
    96  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
    97  				},
    98  			},
    99  		}, {
   100  			name:       "delete 3 nodes with TLS info disabled",
   101  			svcOptions: []serviceoption.Option{serviceoption.WithoutTLSInfo()},
   102  			args: args{
   103  				init: []types.Node{
   104  					{
   105  						Name: "zero",
   106  						IPAddresses: []types.Address{
   107  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   108  						},
   109  					}, {
   110  						Name: "one",
   111  						IPAddresses: []types.Address{
   112  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   113  						},
   114  					}, {
   115  						Name: "two",
   116  						IPAddresses: []types.Address{
   117  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   118  						},
   119  					}, {
   120  						Name:    "one",
   121  						Cluster: "test",
   122  						IPAddresses: []types.Address{
   123  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   124  						},
   125  					}, {
   126  						Name:    "two",
   127  						Cluster: "test",
   128  						IPAddresses: []types.Address{
   129  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   130  						},
   131  					},
   132  				},
   133  				del: []types.Node{
   134  					{
   135  						Name: "one",
   136  						IPAddresses: []types.Address{
   137  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   138  						},
   139  					}, {
   140  						Name: "two",
   141  						IPAddresses: []types.Address{
   142  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   143  						},
   144  					}, {
   145  						Name:    "one",
   146  						Cluster: "test",
   147  						IPAddresses: []types.Address{
   148  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   149  						},
   150  					}, {
   151  						Name:    "two",
   152  						Cluster: "test",
   153  						IPAddresses: []types.Address{
   154  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   155  						},
   156  					},
   157  				},
   158  			},
   159  			want: []*peerpb.ChangeNotification{
   160  				{
   161  					Name:    "zero",
   162  					Address: "192.0.1.1",
   163  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   164  				}, {
   165  					Name:    "one",
   166  					Address: "192.0.2.1",
   167  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   168  				}, {
   169  					Name:    "two",
   170  					Address: "2001:db8::68",
   171  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   172  				}, {
   173  					Name:    "test/one",
   174  					Address: "10.0.10.5",
   175  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   176  				}, {
   177  					Name:    "test/two",
   178  					Address: "10.0.10.6",
   179  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   180  				}, {
   181  					Name:    "one",
   182  					Address: "192.0.2.1",
   183  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   184  				}, {
   185  					Name:    "two",
   186  					Address: "2001:db8::68",
   187  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   188  				}, {
   189  					Name:    "test/one",
   190  					Address: "10.0.10.5",
   191  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   192  				}, {
   193  					Name:    "test/two",
   194  					Address: "10.0.10.6",
   195  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   196  				},
   197  			},
   198  		}, {
   199  			name:       "update 2 nodes with TLS info disabled",
   200  			svcOptions: []serviceoption.Option{serviceoption.WithoutTLSInfo()},
   201  			args: args{
   202  				init: []types.Node{
   203  					{
   204  						Name: "zero",
   205  						IPAddresses: []types.Address{
   206  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   207  						},
   208  					}, {
   209  						Name: "one",
   210  						IPAddresses: []types.Address{
   211  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   212  						},
   213  					}, {
   214  						Name: "two",
   215  						IPAddresses: []types.Address{
   216  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   217  						},
   218  					},
   219  				},
   220  				update: []types.Node{
   221  					{
   222  						Name: "one",
   223  						IPAddresses: []types.Address{
   224  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   225  						},
   226  					}, {
   227  						Name: "one",
   228  						IPAddresses: []types.Address{
   229  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.2")},
   230  						},
   231  					}, {
   232  						Name: "two",
   233  						IPAddresses: []types.Address{
   234  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   235  						},
   236  					}, {
   237  						Name: "two",
   238  						IPAddresses: []types.Address{
   239  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::65")},
   240  						},
   241  					},
   242  				},
   243  			},
   244  			want: []*peerpb.ChangeNotification{
   245  				{
   246  					Name:    "zero",
   247  					Address: "192.0.1.1",
   248  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   249  				}, {
   250  					Name:    "one",
   251  					Address: "192.0.2.1",
   252  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   253  				}, {
   254  					Name:    "two",
   255  					Address: "2001:db8::68",
   256  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   257  				}, {
   258  					Name:    "one",
   259  					Address: "192.0.2.2",
   260  					Type:    peerpb.ChangeNotificationType_PEER_UPDATED,
   261  				}, {
   262  					Name:    "two",
   263  					Address: "2001:db8::65",
   264  					Type:    peerpb.ChangeNotificationType_PEER_UPDATED,
   265  				},
   266  			},
   267  		}, {
   268  			name:       "rename 2 nodes with TLS info disabled",
   269  			svcOptions: []serviceoption.Option{serviceoption.WithoutTLSInfo()},
   270  			args: args{
   271  				init: []types.Node{
   272  					{
   273  						Name: "zero",
   274  						IPAddresses: []types.Address{
   275  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   276  						},
   277  					}, {
   278  						Name: "one",
   279  						IPAddresses: []types.Address{
   280  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   281  						},
   282  					}, {
   283  						Name: "two",
   284  						IPAddresses: []types.Address{
   285  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   286  						},
   287  					},
   288  				},
   289  				update: []types.Node{
   290  					{
   291  						Name: "one",
   292  						IPAddresses: []types.Address{
   293  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   294  						},
   295  					}, {
   296  						Name: "1",
   297  						IPAddresses: []types.Address{
   298  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   299  						},
   300  					}, {
   301  						Name: "two",
   302  						IPAddresses: []types.Address{
   303  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   304  						},
   305  					}, {
   306  						Name: "2",
   307  						IPAddresses: []types.Address{
   308  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   309  						},
   310  					},
   311  				},
   312  			},
   313  			want: []*peerpb.ChangeNotification{
   314  				{
   315  					Name:    "zero",
   316  					Address: "192.0.1.1",
   317  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   318  				}, {
   319  					Name:    "one",
   320  					Address: "192.0.2.1",
   321  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   322  				}, {
   323  					Name:    "two",
   324  					Address: "2001:db8::68",
   325  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   326  				}, {
   327  					Name:    "one",
   328  					Address: "192.0.2.1",
   329  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   330  				}, {
   331  					Name:    "1",
   332  					Address: "192.0.2.1",
   333  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   334  				}, {
   335  					Name:    "two",
   336  					Address: "2001:db8::68",
   337  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   338  				}, {
   339  					Name:    "2",
   340  					Address: "2001:db8::68",
   341  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   342  				},
   343  			},
   344  		}, {
   345  			name: "add 4 nodes",
   346  			args: args{
   347  				init: []types.Node{
   348  					{
   349  						Name: "zero",
   350  						IPAddresses: []types.Address{
   351  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   352  						},
   353  					},
   354  				},
   355  				add: []types.Node{
   356  					{
   357  						Name: "one",
   358  						IPAddresses: []types.Address{
   359  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   360  						},
   361  					}, {
   362  						Name: "two",
   363  						IPAddresses: []types.Address{
   364  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   365  						},
   366  					}, {
   367  						Name:    "one",
   368  						Cluster: "test",
   369  						IPAddresses: []types.Address{
   370  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   371  						},
   372  					}, {
   373  						Name:    "two",
   374  						Cluster: "test",
   375  						IPAddresses: []types.Address{
   376  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   377  						},
   378  					},
   379  				},
   380  			},
   381  			want: []*peerpb.ChangeNotification{
   382  				{
   383  					Name:    "zero",
   384  					Address: "192.0.1.1",
   385  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   386  					Tls: &peerpb.TLS{
   387  						ServerName: "zero.default.hubble-grpc.cilium.io",
   388  					},
   389  				}, {
   390  					Name:    "one",
   391  					Address: "192.0.2.1",
   392  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   393  					Tls: &peerpb.TLS{
   394  						ServerName: "one.default.hubble-grpc.cilium.io",
   395  					},
   396  				}, {
   397  					Name:    "two",
   398  					Address: "2001:db8::68",
   399  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   400  					Tls: &peerpb.TLS{
   401  						ServerName: "two.default.hubble-grpc.cilium.io",
   402  					},
   403  				}, {
   404  					Name:    "test/one",
   405  					Address: "10.0.10.5",
   406  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   407  					Tls: &peerpb.TLS{
   408  						ServerName: "one.test.hubble-grpc.cilium.io",
   409  					},
   410  				}, {
   411  					Name:    "test/two",
   412  					Address: "10.0.10.6",
   413  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   414  					Tls: &peerpb.TLS{
   415  						ServerName: "two.test.hubble-grpc.cilium.io",
   416  					},
   417  				},
   418  			},
   419  		}, {
   420  			name: "delete 3 nodes",
   421  			args: args{
   422  				init: []types.Node{
   423  					{
   424  						Name: "zero",
   425  						IPAddresses: []types.Address{
   426  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   427  						},
   428  					}, {
   429  						Name: "one",
   430  						IPAddresses: []types.Address{
   431  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   432  						},
   433  					}, {
   434  						Name: "two",
   435  						IPAddresses: []types.Address{
   436  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   437  						},
   438  					}, {
   439  						Name:    "one",
   440  						Cluster: "test",
   441  						IPAddresses: []types.Address{
   442  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   443  						},
   444  					}, {
   445  						Name:    "two",
   446  						Cluster: "test",
   447  						IPAddresses: []types.Address{
   448  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   449  						},
   450  					},
   451  				},
   452  				del: []types.Node{
   453  					{
   454  						Name: "one",
   455  						IPAddresses: []types.Address{
   456  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   457  						},
   458  					}, {
   459  						Name: "two",
   460  						IPAddresses: []types.Address{
   461  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   462  						},
   463  					}, {
   464  						Name:    "one",
   465  						Cluster: "test",
   466  						IPAddresses: []types.Address{
   467  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   468  						},
   469  					}, {
   470  						Name:    "two",
   471  						Cluster: "test",
   472  						IPAddresses: []types.Address{
   473  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   474  						},
   475  					},
   476  				},
   477  			},
   478  			want: []*peerpb.ChangeNotification{
   479  				{
   480  					Name:    "zero",
   481  					Address: "192.0.1.1",
   482  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   483  					Tls: &peerpb.TLS{
   484  						ServerName: "zero.default.hubble-grpc.cilium.io",
   485  					},
   486  				}, {
   487  					Name:    "one",
   488  					Address: "192.0.2.1",
   489  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   490  					Tls: &peerpb.TLS{
   491  						ServerName: "one.default.hubble-grpc.cilium.io",
   492  					},
   493  				}, {
   494  					Name:    "two",
   495  					Address: "2001:db8::68",
   496  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   497  					Tls: &peerpb.TLS{
   498  						ServerName: "two.default.hubble-grpc.cilium.io",
   499  					},
   500  				}, {
   501  					Name:    "test/one",
   502  					Address: "10.0.10.5",
   503  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   504  					Tls: &peerpb.TLS{
   505  						ServerName: "one.test.hubble-grpc.cilium.io",
   506  					},
   507  				}, {
   508  					Name:    "test/two",
   509  					Address: "10.0.10.6",
   510  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   511  					Tls: &peerpb.TLS{
   512  						ServerName: "two.test.hubble-grpc.cilium.io",
   513  					},
   514  				}, {
   515  					Name:    "one",
   516  					Address: "192.0.2.1",
   517  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   518  					Tls: &peerpb.TLS{
   519  						ServerName: "one.default.hubble-grpc.cilium.io",
   520  					},
   521  				}, {
   522  					Name:    "two",
   523  					Address: "2001:db8::68",
   524  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   525  					Tls: &peerpb.TLS{
   526  						ServerName: "two.default.hubble-grpc.cilium.io",
   527  					},
   528  				}, {
   529  					Name:    "test/one",
   530  					Address: "10.0.10.5",
   531  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   532  					Tls: &peerpb.TLS{
   533  						ServerName: "one.test.hubble-grpc.cilium.io",
   534  					},
   535  				}, {
   536  					Name:    "test/two",
   537  					Address: "10.0.10.6",
   538  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   539  					Tls: &peerpb.TLS{
   540  						ServerName: "two.test.hubble-grpc.cilium.io",
   541  					},
   542  				},
   543  			},
   544  		}, {
   545  			name: "update 2 nodes",
   546  			args: args{
   547  				init: []types.Node{
   548  					{
   549  						Name: "zero",
   550  						IPAddresses: []types.Address{
   551  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   552  						},
   553  					}, {
   554  						Name: "one",
   555  						IPAddresses: []types.Address{
   556  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   557  						},
   558  					}, {
   559  						Name: "two",
   560  						IPAddresses: []types.Address{
   561  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   562  						},
   563  					},
   564  				},
   565  				update: []types.Node{
   566  					{
   567  						Name: "one",
   568  						IPAddresses: []types.Address{
   569  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   570  						},
   571  					}, {
   572  						Name: "one",
   573  						IPAddresses: []types.Address{
   574  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.2")},
   575  						},
   576  					}, {
   577  						Name: "two",
   578  						IPAddresses: []types.Address{
   579  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   580  						},
   581  					}, {
   582  						Name: "two",
   583  						IPAddresses: []types.Address{
   584  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::65")},
   585  						},
   586  					},
   587  				},
   588  			},
   589  			want: []*peerpb.ChangeNotification{
   590  				{
   591  					Name:    "zero",
   592  					Address: "192.0.1.1",
   593  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   594  					Tls: &peerpb.TLS{
   595  						ServerName: "zero.default.hubble-grpc.cilium.io",
   596  					},
   597  				}, {
   598  					Name:    "one",
   599  					Address: "192.0.2.1",
   600  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   601  					Tls: &peerpb.TLS{
   602  						ServerName: "one.default.hubble-grpc.cilium.io",
   603  					},
   604  				}, {
   605  					Name:    "two",
   606  					Address: "2001:db8::68",
   607  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   608  					Tls: &peerpb.TLS{
   609  						ServerName: "two.default.hubble-grpc.cilium.io",
   610  					},
   611  				}, {
   612  					Name:    "one",
   613  					Address: "192.0.2.2",
   614  					Type:    peerpb.ChangeNotificationType_PEER_UPDATED,
   615  					Tls: &peerpb.TLS{
   616  						ServerName: "one.default.hubble-grpc.cilium.io",
   617  					},
   618  				}, {
   619  					Name:    "two",
   620  					Address: "2001:db8::65",
   621  					Type:    peerpb.ChangeNotificationType_PEER_UPDATED,
   622  					Tls: &peerpb.TLS{
   623  						ServerName: "two.default.hubble-grpc.cilium.io",
   624  					},
   625  				},
   626  			},
   627  		}, {
   628  			name: "rename 2 nodes",
   629  			args: args{
   630  				init: []types.Node{
   631  					{
   632  						Name: "zero",
   633  						IPAddresses: []types.Address{
   634  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.1.1")},
   635  						},
   636  					}, {
   637  						Name: "one",
   638  						IPAddresses: []types.Address{
   639  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   640  						},
   641  					}, {
   642  						Name: "two",
   643  						IPAddresses: []types.Address{
   644  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   645  						},
   646  					},
   647  				},
   648  				update: []types.Node{
   649  					{
   650  						Name: "one",
   651  						IPAddresses: []types.Address{
   652  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   653  						},
   654  					}, {
   655  						Name: "1",
   656  						IPAddresses: []types.Address{
   657  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   658  						},
   659  					}, {
   660  						Name: "two",
   661  						IPAddresses: []types.Address{
   662  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   663  						},
   664  					}, {
   665  						Name: "2",
   666  						IPAddresses: []types.Address{
   667  							{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   668  						},
   669  					},
   670  				},
   671  			},
   672  			want: []*peerpb.ChangeNotification{
   673  				{
   674  					Name:    "zero",
   675  					Address: "192.0.1.1",
   676  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   677  					Tls: &peerpb.TLS{
   678  						ServerName: "zero.default.hubble-grpc.cilium.io",
   679  					},
   680  				}, {
   681  					Name:    "one",
   682  					Address: "192.0.2.1",
   683  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   684  					Tls: &peerpb.TLS{
   685  						ServerName: "one.default.hubble-grpc.cilium.io",
   686  					},
   687  				}, {
   688  					Name:    "two",
   689  					Address: "2001:db8::68",
   690  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   691  					Tls: &peerpb.TLS{
   692  						ServerName: "two.default.hubble-grpc.cilium.io",
   693  					},
   694  				}, {
   695  					Name:    "one",
   696  					Address: "192.0.2.1",
   697  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   698  					Tls: &peerpb.TLS{
   699  						ServerName: "one.default.hubble-grpc.cilium.io",
   700  					},
   701  				}, {
   702  					Name:    "1",
   703  					Address: "192.0.2.1",
   704  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   705  					Tls: &peerpb.TLS{
   706  						ServerName: "1.default.hubble-grpc.cilium.io",
   707  					},
   708  				}, {
   709  					Name:    "two",
   710  					Address: "2001:db8::68",
   711  					Type:    peerpb.ChangeNotificationType_PEER_DELETED,
   712  					Tls: &peerpb.TLS{
   713  						ServerName: "two.default.hubble-grpc.cilium.io",
   714  					},
   715  				}, {
   716  					Name:    "2",
   717  					Address: "2001:db8::68",
   718  					Type:    peerpb.ChangeNotificationType_PEER_ADDED,
   719  					Tls: &peerpb.TLS{
   720  						ServerName: "2.default.hubble-grpc.cilium.io",
   721  					},
   722  				},
   723  			},
   724  		},
   725  	}
   726  	for _, tt := range tests {
   727  		t.Run(tt.name, func(t *testing.T) {
   728  			var got []*peerpb.ChangeNotification
   729  			var wg sync.WaitGroup
   730  			fakeServer := &testutils.FakePeerNotifyServer{
   731  				OnSend: func(resp *peerpb.ChangeNotification) error {
   732  					got = append(got, resp)
   733  					wg.Done()
   734  					return nil
   735  				},
   736  			}
   737  			ready := make(chan struct{})
   738  			cb := func(nh datapath.NodeHandler) {
   739  				ready <- struct{}{}
   740  			}
   741  			notif := newNotifier(cb, tt.args.init)
   742  			wg.Add(len(tt.args.init))
   743  			svc := NewService(notif, tt.svcOptions...)
   744  			done := make(chan struct{})
   745  			go func() {
   746  				err := svc.Notify(&peerpb.NotifyRequest{}, fakeServer)
   747  				assert.NoError(t, err)
   748  				close(done)
   749  			}()
   750  			<-ready
   751  			for _, n := range tt.args.add {
   752  				wg.Add(1)
   753  				notif.notifyAdd(n)
   754  			}
   755  			for _, n := range tt.args.del {
   756  				wg.Add(1)
   757  				notif.notifyDelete(n)
   758  			}
   759  			// the update slice shall always be even with odd entry
   760  			// corresponding to the old node and following even entries to the
   761  			// updated one
   762  			var o types.Node
   763  			for i, n := range tt.args.update {
   764  				if i%2 == 0 {
   765  					n := n
   766  					o = n
   767  					continue
   768  				}
   769  				// the number of notifications we expect depends on the change
   770  				// - identical: no notification
   771  				// - name change: 2 notifications
   772  				// - other change: 1 notification
   773  				switch {
   774  				case cmp.Diff(o, n) == "":
   775  					// no-op
   776  				case o.Name != n.Name:
   777  					wg.Add(2)
   778  				default:
   779  					wg.Add(1)
   780  				}
   781  				notif.notifyUpdate(o, n)
   782  			}
   783  			wg.Wait()
   784  			svc.Close()
   785  			assert.Equal(t, tt.want, got)
   786  			// wait for the notify call routine to finish
   787  			<-done
   788  		})
   789  	}
   790  }
   791  
   792  func TestService_NotifyWithBlockedSend(t *testing.T) {
   793  	fakeServer := &testutils.FakePeerNotifyServer{
   794  		OnSend: func(resp *peerpb.ChangeNotification) error {
   795  			<-time.After(100 * time.Millisecond)
   796  			return nil
   797  		},
   798  	}
   799  	ready := make(chan struct{})
   800  	cb := func(nh datapath.NodeHandler) {
   801  		ready <- struct{}{}
   802  	}
   803  	init := []types.Node{
   804  		{
   805  			Name: "one",
   806  			IPAddresses: []types.Address{
   807  				{Type: addressing.NodeInternalIP, IP: net.ParseIP("192.0.2.1")},
   808  			},
   809  		}, {
   810  			Name: "two",
   811  			IPAddresses: []types.Address{
   812  				{Type: addressing.NodeInternalIP, IP: net.ParseIP("2001:db8::68")},
   813  			},
   814  		}, {
   815  			Name:    "one",
   816  			Cluster: "test",
   817  			IPAddresses: []types.Address{
   818  				{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.5")},
   819  			},
   820  		}, {
   821  			Name:    "two",
   822  			Cluster: "test",
   823  			IPAddresses: []types.Address{
   824  				{Type: addressing.NodeInternalIP, IP: net.ParseIP("10.0.10.6")},
   825  			},
   826  		},
   827  	}
   828  	notif := newNotifier(cb, init)
   829  	svc := NewService(notif, serviceoption.WithMaxSendBufferSize(2), serviceoption.WithoutTLSInfo())
   830  	done := make(chan struct{})
   831  	go func() {
   832  		err := svc.Notify(&peerpb.NotifyRequest{}, fakeServer)
   833  		assert.Equal(t, ErrStreamSendBlocked, err)
   834  		close(done)
   835  	}()
   836  	<-ready
   837  	for _, n := range init {
   838  		notif.notifyAdd(n)
   839  	}
   840  	svc.Close()
   841  	// wait for the notify call routine to finish
   842  	<-done
   843  }
   844  
   845  type notifier struct {
   846  	nodes       []types.Node
   847  	subscribers map[datapath.NodeHandler]struct{}
   848  	cb          func(nh datapath.NodeHandler)
   849  	mu          lock.Mutex
   850  }
   851  
   852  var _ manager.Notifier = (*notifier)(nil)
   853  
   854  func newNotifier(subCallback func(nh datapath.NodeHandler), nodes []types.Node) *notifier {
   855  	return &notifier{
   856  		nodes:       nodes,
   857  		subscribers: make(map[datapath.NodeHandler]struct{}),
   858  		cb:          subCallback,
   859  	}
   860  }
   861  
   862  func (n *notifier) Subscribe(nh datapath.NodeHandler) {
   863  	n.mu.Lock()
   864  	n.subscribers[nh] = struct{}{}
   865  	n.mu.Unlock()
   866  	for _, e := range n.nodes {
   867  		nh.NodeAdd(e)
   868  	}
   869  	if n.cb != nil {
   870  		n.cb(nh)
   871  	}
   872  }
   873  
   874  func (n *notifier) Unsubscribe(nh datapath.NodeHandler) {
   875  	n.mu.Lock()
   876  	delete(n.subscribers, nh)
   877  	n.mu.Unlock()
   878  }
   879  
   880  func (n *notifier) notifyAdd(e types.Node) {
   881  	n.mu.Lock()
   882  	for s := range n.subscribers {
   883  		s.NodeAdd(e)
   884  	}
   885  	n.mu.Unlock()
   886  }
   887  
   888  func (n *notifier) notifyDelete(e types.Node) {
   889  	n.mu.Lock()
   890  	for s := range n.subscribers {
   891  		s.NodeDelete(e)
   892  	}
   893  	n.mu.Unlock()
   894  }
   895  
   896  func (n *notifier) notifyUpdate(o, e types.Node) {
   897  	n.mu.Lock()
   898  	for s := range n.subscribers {
   899  		s.NodeUpdate(o, e)
   900  	}
   901  	n.mu.Unlock()
   902  }