github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/allocator/cnmallocator/portallocator_test.go (about)

     1  package cnmallocator
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/docker/swarmkit/api"
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestReconcilePortConfigs(t *testing.T) {
    11  	type portConfigsBind struct {
    12  		input  *api.Service
    13  		expect []*api.PortConfig
    14  	}
    15  
    16  	portConfigsBinds := []portConfigsBind{
    17  		{
    18  			input: &api.Service{
    19  				Spec: api.ServiceSpec{
    20  					Endpoint: &api.EndpointSpec{
    21  						Ports: []*api.PortConfig{
    22  							{
    23  								Name:          "test1",
    24  								Protocol:      api.ProtocolTCP,
    25  								TargetPort:    10000,
    26  								PublishedPort: 10000,
    27  							},
    28  						},
    29  					},
    30  				},
    31  				Endpoint: nil,
    32  			},
    33  			expect: []*api.PortConfig{
    34  				{
    35  					Name:          "test1",
    36  					Protocol:      api.ProtocolTCP,
    37  					TargetPort:    10000,
    38  					PublishedPort: 10000,
    39  				},
    40  			},
    41  		},
    42  		{
    43  			input: &api.Service{
    44  				Spec: api.ServiceSpec{
    45  					Endpoint: &api.EndpointSpec{
    46  						Ports: []*api.PortConfig{
    47  							{
    48  								Name:          "test1",
    49  								Protocol:      api.ProtocolTCP,
    50  								TargetPort:    10000,
    51  								PublishedPort: 10000,
    52  							},
    53  							{
    54  								Name:          "test2",
    55  								Protocol:      api.ProtocolTCP,
    56  								TargetPort:    10001,
    57  								PublishedPort: 10001,
    58  							},
    59  						},
    60  					},
    61  				},
    62  				Endpoint: &api.Endpoint{
    63  					Ports: []*api.PortConfig{
    64  						{
    65  							Name:          "test1",
    66  							Protocol:      api.ProtocolTCP,
    67  							TargetPort:    10000,
    68  							PublishedPort: 10000,
    69  						},
    70  					},
    71  				},
    72  			},
    73  			expect: []*api.PortConfig{
    74  				{
    75  					Name:          "test1",
    76  					Protocol:      api.ProtocolTCP,
    77  					TargetPort:    10000,
    78  					PublishedPort: 10000,
    79  				},
    80  				{
    81  					Name:          "test2",
    82  					Protocol:      api.ProtocolTCP,
    83  					TargetPort:    10001,
    84  					PublishedPort: 10001,
    85  				},
    86  			},
    87  		},
    88  		{
    89  			input: &api.Service{
    90  				Spec: api.ServiceSpec{
    91  					Endpoint: &api.EndpointSpec{
    92  						Ports: []*api.PortConfig{
    93  							{
    94  								Name:          "test1",
    95  								Protocol:      api.ProtocolTCP,
    96  								TargetPort:    10000,
    97  								PublishedPort: 10000,
    98  							},
    99  						},
   100  					},
   101  				},
   102  				Endpoint: &api.Endpoint{
   103  					Ports: []*api.PortConfig{
   104  						{
   105  							Name:          "test2",
   106  							Protocol:      api.ProtocolTCP,
   107  							TargetPort:    10001,
   108  							PublishedPort: 10000,
   109  						},
   110  					},
   111  				},
   112  			},
   113  			expect: []*api.PortConfig{
   114  				{
   115  					Name:          "test1",
   116  					Protocol:      api.ProtocolTCP,
   117  					TargetPort:    10000,
   118  					PublishedPort: 10000,
   119  				},
   120  			},
   121  		},
   122  		{
   123  			input: &api.Service{
   124  				Spec: api.ServiceSpec{
   125  					Endpoint: &api.EndpointSpec{
   126  						Ports: []*api.PortConfig{
   127  							{
   128  								Name:          "test1",
   129  								Protocol:      api.ProtocolTCP,
   130  								TargetPort:    10000,
   131  								PublishedPort: 0,
   132  							},
   133  							{
   134  								Name:          "test2",
   135  								Protocol:      api.ProtocolTCP,
   136  								TargetPort:    10001,
   137  								PublishedPort: 0,
   138  							},
   139  						},
   140  					},
   141  				},
   142  				Endpoint: &api.Endpoint{
   143  					Ports: []*api.PortConfig{
   144  						{
   145  							Name:          "test2",
   146  							Protocol:      api.ProtocolTCP,
   147  							TargetPort:    10001,
   148  							PublishedPort: 10001,
   149  						},
   150  						{
   151  							Name:          "test1",
   152  							Protocol:      api.ProtocolTCP,
   153  							TargetPort:    10000,
   154  							PublishedPort: 10000,
   155  						},
   156  					},
   157  				},
   158  			},
   159  			expect: []*api.PortConfig{
   160  				{
   161  					Name:          "test1",
   162  					Protocol:      api.ProtocolTCP,
   163  					TargetPort:    10000,
   164  					PublishedPort: 10000,
   165  				},
   166  				{
   167  					Name:          "test2",
   168  					Protocol:      api.ProtocolTCP,
   169  					TargetPort:    10001,
   170  					PublishedPort: 10001,
   171  				},
   172  			},
   173  		},
   174  	}
   175  
   176  	for _, singleTest := range portConfigsBinds {
   177  		expect := reconcilePortConfigs(singleTest.input)
   178  		assert.Equal(t, singleTest.expect, expect)
   179  	}
   180  }
   181  
   182  func TestAllocateServicePorts(t *testing.T) {
   183  	pa, err := newPortAllocator()
   184  	assert.NoError(t, err)
   185  
   186  	// Service has no endpoint in ServiceSpec
   187  	s := &api.Service{
   188  		Spec: api.ServiceSpec{
   189  			Endpoint: nil,
   190  		},
   191  		Endpoint: &api.Endpoint{
   192  			Ports: []*api.PortConfig{
   193  				{
   194  					Name:          "test1",
   195  					Protocol:      api.ProtocolTCP,
   196  					TargetPort:    10000,
   197  					PublishedPort: 10000,
   198  				},
   199  			},
   200  		},
   201  	}
   202  
   203  	err = pa.serviceAllocatePorts(s)
   204  	assert.NoError(t, err)
   205  
   206  	// Service has a published port 10001 in ServiceSpec
   207  	s = &api.Service{
   208  		Spec: api.ServiceSpec{
   209  			Endpoint: &api.EndpointSpec{
   210  				Ports: []*api.PortConfig{
   211  					{
   212  						Name:          "test1",
   213  						Protocol:      api.ProtocolTCP,
   214  						TargetPort:    10000,
   215  						PublishedPort: 10001,
   216  					},
   217  				},
   218  			},
   219  		},
   220  		Endpoint: &api.Endpoint{
   221  			Ports: []*api.PortConfig{
   222  				{
   223  					Name:          "test1",
   224  					Protocol:      api.ProtocolTCP,
   225  					TargetPort:    10000,
   226  					PublishedPort: 10000,
   227  				},
   228  			},
   229  		},
   230  	}
   231  
   232  	err = pa.serviceAllocatePorts(s)
   233  	assert.NoError(t, err)
   234  
   235  	// Service has a published port 10001 in ServiceSpec
   236  	// which is already allocated on host
   237  	s = &api.Service{
   238  		Spec: api.ServiceSpec{
   239  			Endpoint: &api.EndpointSpec{
   240  				Ports: []*api.PortConfig{
   241  					{
   242  						Name:          "test1",
   243  						Protocol:      api.ProtocolTCP,
   244  						TargetPort:    10000,
   245  						PublishedPort: 10001,
   246  					},
   247  				},
   248  			},
   249  		},
   250  		Endpoint: &api.Endpoint{
   251  			Ports: []*api.PortConfig{
   252  				{
   253  					Name:          "test1",
   254  					Protocol:      api.ProtocolTCP,
   255  					TargetPort:    10000,
   256  					PublishedPort: 10000,
   257  				},
   258  			},
   259  		},
   260  	}
   261  
   262  	// port allocated already, got an error
   263  	err = pa.serviceAllocatePorts(s)
   264  	assert.Error(t, err)
   265  }
   266  
   267  func TestHostPublishPortsNeedUpdate(t *testing.T) {
   268  	pa, err := newPortAllocator()
   269  	assert.NoError(t, err)
   270  
   271  	type Data struct {
   272  		name   string
   273  		input  *api.Service
   274  		expect bool
   275  	}
   276  
   277  	testCases := []Data{
   278  		{
   279  			// both Endpoint and Spec.Endpoint are nil
   280  			name: "NilEndpointAndSpec",
   281  			input: &api.Service{
   282  				Spec: api.ServiceSpec{
   283  					Endpoint: nil,
   284  				},
   285  				Endpoint: nil,
   286  			},
   287  			expect: false,
   288  		},
   289  		{
   290  			// non host mode does not impact
   291  			name: "NonHostModePort",
   292  			input: &api.Service{
   293  				Spec: api.ServiceSpec{
   294  					Endpoint: &api.EndpointSpec{
   295  						Ports: []*api.PortConfig{
   296  							{
   297  								Name:          "test1",
   298  								Protocol:      api.ProtocolTCP,
   299  								TargetPort:    10000,
   300  								PublishedPort: 10000,
   301  							},
   302  						},
   303  					},
   304  				},
   305  				Endpoint: nil,
   306  			},
   307  			expect: false,
   308  		},
   309  		{
   310  			// publish mode is different
   311  			name: "PublishModeDifferent",
   312  			input: &api.Service{
   313  				Spec: api.ServiceSpec{
   314  					Endpoint: &api.EndpointSpec{
   315  						Ports: []*api.PortConfig{
   316  							{
   317  								Name:          "test1",
   318  								Protocol:      api.ProtocolTCP,
   319  								TargetPort:    10000,
   320  								PublishedPort: 10000,
   321  								PublishMode:   api.PublishModeHost,
   322  							},
   323  						},
   324  					},
   325  				},
   326  				Endpoint: &api.Endpoint{
   327  					Ports: []*api.PortConfig{
   328  						{
   329  							Name:          "test1",
   330  							Protocol:      api.ProtocolTCP,
   331  							TargetPort:    10000,
   332  							PublishedPort: 10000,
   333  						},
   334  					},
   335  				},
   336  			},
   337  			expect: true,
   338  		},
   339  		{
   340  			name: "NothingChanged",
   341  			input: &api.Service{
   342  				Spec: api.ServiceSpec{
   343  					Endpoint: &api.EndpointSpec{
   344  						Ports: []*api.PortConfig{
   345  							{
   346  								Name:          "test1",
   347  								Protocol:      api.ProtocolTCP,
   348  								TargetPort:    10000,
   349  								PublishedPort: 10000,
   350  								PublishMode:   api.PublishModeHost,
   351  							},
   352  						},
   353  					},
   354  				},
   355  				Endpoint: &api.Endpoint{
   356  					Ports: []*api.PortConfig{
   357  						{
   358  							Name:          "test1",
   359  							Protocol:      api.ProtocolTCP,
   360  							TargetPort:    10000,
   361  							PublishedPort: 10000,
   362  							PublishMode:   api.PublishModeHost,
   363  						},
   364  					},
   365  				},
   366  			},
   367  			expect: false,
   368  		},
   369  		{
   370  			// published port not specified
   371  			// we are not in charge of allocating one, for us it
   372  			// is as allocated, we need to skip the allocation
   373  			name: "PublishPortNotSpecified",
   374  			input: &api.Service{
   375  				Spec: api.ServiceSpec{
   376  					Endpoint: &api.EndpointSpec{
   377  						Ports: []*api.PortConfig{
   378  							{
   379  								Name:        "test4",
   380  								Protocol:    api.ProtocolUDP,
   381  								TargetPort:  99,
   382  								PublishMode: api.PublishModeHost,
   383  							},
   384  						},
   385  					},
   386  				},
   387  				Endpoint: &api.Endpoint{
   388  					Ports: []*api.PortConfig{
   389  						{
   390  							Name:        "test4",
   391  							Protocol:    api.ProtocolUDP,
   392  							TargetPort:  99,
   393  							PublishMode: api.PublishModeHost,
   394  						},
   395  					},
   396  				},
   397  			},
   398  			expect: false,
   399  		},
   400  		{
   401  			// one published port not specified, the other specified
   402  			// we are still in charge of allocating one
   403  			name: "OnePublishPortSpecifiedButDone",
   404  			input: &api.Service{
   405  				Spec: api.ServiceSpec{
   406  					Endpoint: &api.EndpointSpec{
   407  						Ports: []*api.PortConfig{
   408  							{
   409  								Name:        "test5",
   410  								Protocol:    api.ProtocolUDP,
   411  								TargetPort:  99,
   412  								PublishMode: api.PublishModeHost,
   413  							},
   414  							{
   415  								Name:          "test5",
   416  								Protocol:      api.ProtocolTCP,
   417  								TargetPort:    99,
   418  								PublishedPort: 30099,
   419  								PublishMode:   api.PublishModeHost,
   420  							},
   421  						},
   422  					},
   423  				},
   424  				Endpoint: &api.Endpoint{
   425  					Ports: []*api.PortConfig{
   426  						{
   427  							Name:        "test5",
   428  							Protocol:    api.ProtocolUDP,
   429  							TargetPort:  99,
   430  							PublishMode: api.PublishModeHost,
   431  						},
   432  						{
   433  							Name:        "test5",
   434  							Protocol:    api.ProtocolTCP,
   435  							TargetPort:  99,
   436  							PublishMode: api.PublishModeHost,
   437  						},
   438  					},
   439  				},
   440  			},
   441  			expect: true,
   442  		},
   443  		{
   444  			// one published port not specified, the other specified
   445  			// we are still in charge of allocating one and we did.
   446  			name: "OnePublishPortSpecifiedButDone",
   447  			input: &api.Service{
   448  				Spec: api.ServiceSpec{
   449  					Endpoint: &api.EndpointSpec{
   450  						Ports: []*api.PortConfig{
   451  							{
   452  								Name:        "test6",
   453  								Protocol:    api.ProtocolUDP,
   454  								TargetPort:  99,
   455  								PublishMode: api.PublishModeHost,
   456  							},
   457  							{
   458  								Name:          "test6",
   459  								Protocol:      api.ProtocolTCP,
   460  								TargetPort:    99,
   461  								PublishedPort: 30099,
   462  								PublishMode:   api.PublishModeHost,
   463  							},
   464  						},
   465  					},
   466  				},
   467  				Endpoint: &api.Endpoint{
   468  					Ports: []*api.PortConfig{
   469  						{
   470  							Name:        "test6",
   471  							Protocol:    api.ProtocolUDP,
   472  							TargetPort:  99,
   473  							PublishMode: api.PublishModeHost,
   474  						},
   475  						{
   476  							Name:          "test6",
   477  							Protocol:      api.ProtocolTCP,
   478  							TargetPort:    99,
   479  							PublishedPort: 30099,
   480  							PublishMode:   api.PublishModeHost,
   481  						},
   482  					},
   483  				},
   484  			},
   485  			expect: false,
   486  		},
   487  	}
   488  	for _, singleTest := range testCases {
   489  		t.Run(singleTest.name, func(t *testing.T) {
   490  			actual := pa.hostPublishPortsNeedUpdate(singleTest.input)
   491  			assert.Equal(t, singleTest.expect, actual)
   492  		})
   493  	}
   494  }
   495  
   496  func TestIsPortsAllocated(t *testing.T) {
   497  	pa, err := newPortAllocator()
   498  	assert.NoError(t, err)
   499  
   500  	type Data struct {
   501  		name   string
   502  		input  *api.Service
   503  		expect bool
   504  	}
   505  
   506  	testCases := []Data{
   507  		{
   508  			// both Endpoint and Spec.Endpoint are nil
   509  			name: "BothNil",
   510  			input: &api.Service{
   511  				Spec: api.ServiceSpec{
   512  					Endpoint: nil,
   513  				},
   514  				Endpoint: nil,
   515  			},
   516  			expect: true,
   517  		},
   518  		{
   519  			// Endpoint is non-nil and Spec.Endpoint is nil
   520  			name: "NilSpec",
   521  			input: &api.Service{
   522  				Spec: api.ServiceSpec{
   523  					Endpoint: &api.EndpointSpec{
   524  						Ports: []*api.PortConfig{
   525  							{
   526  								Name:          "test1",
   527  								Protocol:      api.ProtocolTCP,
   528  								TargetPort:    10000,
   529  								PublishedPort: 10000,
   530  							},
   531  						},
   532  					},
   533  				},
   534  				Endpoint: nil,
   535  			},
   536  			expect: false,
   537  		},
   538  		{
   539  			// Endpoint is nil and Spec.Endpoint is non-nil
   540  			name: "NilEndpoint",
   541  			input: &api.Service{
   542  				Spec: api.ServiceSpec{
   543  					Endpoint: nil,
   544  				},
   545  				Endpoint: &api.Endpoint{
   546  					Ports: []*api.PortConfig{
   547  						{
   548  							Name:          "test2",
   549  							Protocol:      api.ProtocolTCP,
   550  							TargetPort:    10001,
   551  							PublishedPort: 10000,
   552  						},
   553  					},
   554  				},
   555  			},
   556  			expect: false,
   557  		},
   558  		{
   559  			// Endpoint and Spec.Endpoint have different length
   560  			name: "DifferentLengths",
   561  			input: &api.Service{
   562  				Spec: api.ServiceSpec{
   563  					Endpoint: &api.EndpointSpec{
   564  						Ports: []*api.PortConfig{
   565  							{
   566  								Name:          "test1",
   567  								Protocol:      api.ProtocolTCP,
   568  								TargetPort:    10000,
   569  								PublishedPort: 10000,
   570  							},
   571  							{
   572  								Name:          "test2",
   573  								Protocol:      api.ProtocolTCP,
   574  								TargetPort:    10001,
   575  								PublishedPort: 10001,
   576  							},
   577  						},
   578  					},
   579  				},
   580  				Endpoint: &api.Endpoint{
   581  					Ports: []*api.PortConfig{
   582  						{
   583  							Name:          "test2",
   584  							Protocol:      api.ProtocolTCP,
   585  							TargetPort:    10001,
   586  							PublishedPort: 10000,
   587  						},
   588  					},
   589  				},
   590  			},
   591  			expect: false,
   592  		},
   593  		{
   594  			// Endpoint and Spec.Endpoint have different TargetPort
   595  			name: "DifferentTargetPort",
   596  			input: &api.Service{
   597  				Spec: api.ServiceSpec{
   598  					Endpoint: &api.EndpointSpec{
   599  						Ports: []*api.PortConfig{
   600  							{
   601  								Name:          "test1",
   602  								Protocol:      api.ProtocolTCP,
   603  								TargetPort:    10001,
   604  								PublishedPort: 10000,
   605  							},
   606  						},
   607  					},
   608  				},
   609  				Endpoint: &api.Endpoint{
   610  					Ports: []*api.PortConfig{
   611  						{
   612  							Name:          "test1",
   613  							Protocol:      api.ProtocolTCP,
   614  							TargetPort:    10000,
   615  							PublishedPort: 10000,
   616  						},
   617  					},
   618  				},
   619  			},
   620  			expect: false,
   621  		},
   622  		{
   623  			// Endpoint and Spec.Endpoint have different PublishedPort
   624  			name: "DifferentPublishedPort",
   625  			input: &api.Service{
   626  				Spec: api.ServiceSpec{
   627  					Endpoint: &api.EndpointSpec{
   628  						Ports: []*api.PortConfig{
   629  							{
   630  								Name:          "test1",
   631  								Protocol:      api.ProtocolTCP,
   632  								TargetPort:    10000,
   633  								PublishedPort: 10001,
   634  							},
   635  						},
   636  					},
   637  				},
   638  				Endpoint: &api.Endpoint{
   639  					Ports: []*api.PortConfig{
   640  						{
   641  							Name:          "test1",
   642  							Protocol:      api.ProtocolTCP,
   643  							TargetPort:    10000,
   644  							PublishedPort: 10000,
   645  						},
   646  					},
   647  				},
   648  			},
   649  			expect: false,
   650  		},
   651  		{
   652  			// Endpoint and Spec.Endpoint are the same and PublishedPort is 0
   653  			name: "NotYetAssignedPublishedPort",
   654  			input: &api.Service{
   655  				Spec: api.ServiceSpec{
   656  					Endpoint: &api.EndpointSpec{
   657  						Ports: []*api.PortConfig{
   658  							{
   659  								Name:          "test1",
   660  								Protocol:      api.ProtocolTCP,
   661  								TargetPort:    10000,
   662  								PublishedPort: 0,
   663  							},
   664  						},
   665  					},
   666  				},
   667  				Endpoint: &api.Endpoint{
   668  					Ports: []*api.PortConfig{
   669  						{
   670  							Name:          "test1",
   671  							Protocol:      api.ProtocolTCP,
   672  							TargetPort:    10000,
   673  							PublishedPort: 0,
   674  						},
   675  					},
   676  				},
   677  			},
   678  			expect: false,
   679  		},
   680  		{
   681  			// Endpoint and Spec.Endpoint are the same and PublishedPort is non-0
   682  			name: "NonzeroPublishedPort",
   683  			input: &api.Service{
   684  				Spec: api.ServiceSpec{
   685  					Endpoint: &api.EndpointSpec{
   686  						Ports: []*api.PortConfig{
   687  							{
   688  								Name:          "test1",
   689  								Protocol:      api.ProtocolTCP,
   690  								TargetPort:    10000,
   691  								PublishedPort: 10000,
   692  							},
   693  						},
   694  					},
   695  				},
   696  				Endpoint: &api.Endpoint{
   697  					Ports: []*api.PortConfig{
   698  						{
   699  							Name:          "test1",
   700  							Protocol:      api.ProtocolTCP,
   701  							TargetPort:    10000,
   702  							PublishedPort: 10000,
   703  						},
   704  					},
   705  				},
   706  			},
   707  			expect: true,
   708  		},
   709  		{
   710  			// Endpoint and Spec.Endpoint are the same except PublishedPort, and PublishedPort in Endpoint is non-0
   711  			name: "AlreadyAssignedPublishedPort",
   712  			input: &api.Service{
   713  				Spec: api.ServiceSpec{
   714  					Endpoint: &api.EndpointSpec{
   715  						Ports: []*api.PortConfig{
   716  							{
   717  								Name:          "test1",
   718  								Protocol:      api.ProtocolTCP,
   719  								TargetPort:    10000,
   720  								PublishedPort: 0,
   721  							},
   722  						},
   723  					},
   724  				},
   725  				Endpoint: &api.Endpoint{
   726  					Ports: []*api.PortConfig{
   727  						{
   728  							Name:          "test1",
   729  							Protocol:      api.ProtocolTCP,
   730  							TargetPort:    10000,
   731  							PublishedPort: 10000,
   732  						},
   733  					},
   734  				},
   735  			},
   736  			expect: true,
   737  		},
   738  		{
   739  			// Endpoint and Spec.Endpoint are the same except the ports are in different order
   740  			name: "DifferentOrders",
   741  			input: &api.Service{
   742  				Spec: api.ServiceSpec{
   743  					Endpoint: &api.EndpointSpec{
   744  						Ports: []*api.PortConfig{
   745  							{
   746  								Name:          "test1",
   747  								Protocol:      api.ProtocolTCP,
   748  								TargetPort:    10000,
   749  								PublishedPort: 0,
   750  							},
   751  							{
   752  								Name:          "test2",
   753  								Protocol:      api.ProtocolTCP,
   754  								TargetPort:    10001,
   755  								PublishedPort: 0,
   756  							},
   757  							{
   758  								Name:          "test3",
   759  								Protocol:      api.ProtocolTCP,
   760  								TargetPort:    10002,
   761  								PublishedPort: 0,
   762  								PublishMode:   api.PublishModeHost,
   763  							},
   764  						},
   765  					},
   766  				},
   767  				Endpoint: &api.Endpoint{
   768  					Ports: []*api.PortConfig{
   769  						{
   770  							Name:          "test2",
   771  							Protocol:      api.ProtocolTCP,
   772  							TargetPort:    10001,
   773  							PublishedPort: 10001,
   774  						},
   775  						{
   776  							Name:          "test3",
   777  							Protocol:      api.ProtocolTCP,
   778  							TargetPort:    10002,
   779  							PublishedPort: 0,
   780  							PublishMode:   api.PublishModeHost,
   781  						},
   782  						{
   783  							Name:          "test1",
   784  							Protocol:      api.ProtocolTCP,
   785  							TargetPort:    10000,
   786  							PublishedPort: 10000,
   787  						},
   788  					},
   789  				},
   790  			},
   791  			expect: true,
   792  		},
   793  		{
   794  			// Endpoint and Spec.Endpoint have multiple PublishedPort
   795  			// See docker/docker#29730
   796  			name: "MultiplePublishedPort",
   797  			input: &api.Service{
   798  				Spec: api.ServiceSpec{
   799  					Endpoint: &api.EndpointSpec{
   800  						Ports: []*api.PortConfig{
   801  							{
   802  								Protocol:      api.ProtocolTCP,
   803  								TargetPort:    80,
   804  								PublishedPort: 5000,
   805  							},
   806  							{
   807  								Protocol:      api.ProtocolTCP,
   808  								TargetPort:    80,
   809  								PublishedPort: 5001,
   810  							},
   811  							{
   812  								Protocol:      api.ProtocolTCP,
   813  								TargetPort:    80,
   814  								PublishedPort: 0,
   815  							},
   816  							{
   817  								Protocol:      api.ProtocolTCP,
   818  								TargetPort:    80,
   819  								PublishedPort: 0,
   820  							},
   821  						},
   822  					},
   823  				},
   824  				Endpoint: &api.Endpoint{
   825  					Ports: []*api.PortConfig{
   826  						{
   827  							Protocol:      api.ProtocolTCP,
   828  							TargetPort:    80,
   829  							PublishedPort: 5000,
   830  						},
   831  						{
   832  							Protocol:      api.ProtocolTCP,
   833  							TargetPort:    80,
   834  							PublishedPort: 5001,
   835  						},
   836  						{
   837  							Protocol:      api.ProtocolTCP,
   838  							TargetPort:    80,
   839  							PublishedPort: 30000,
   840  						},
   841  						{
   842  							Protocol:      api.ProtocolTCP,
   843  							TargetPort:    80,
   844  							PublishedPort: 30001,
   845  						},
   846  					},
   847  				},
   848  			},
   849  			expect: true,
   850  		},
   851  		{
   852  			// one published host port is removed and another is added
   853  			name: "DifferentTargetPortHostMode",
   854  			input: &api.Service{
   855  				Spec: api.ServiceSpec{
   856  					Endpoint: &api.EndpointSpec{
   857  						Ports: []*api.PortConfig{
   858  							{
   859  								Protocol:    api.ProtocolTCP,
   860  								TargetPort:  99,
   861  								PublishMode: api.PublishModeHost,
   862  							},
   863  						},
   864  					},
   865  				},
   866  				Endpoint: &api.Endpoint{
   867  					Ports: []*api.PortConfig{
   868  						{
   869  							Protocol:    api.ProtocolTCP,
   870  							TargetPort:  77,
   871  							PublishMode: api.PublishModeHost,
   872  						},
   873  					},
   874  				},
   875  			},
   876  			expect: false,
   877  		},
   878  	}
   879  
   880  	for _, singleTest := range testCases {
   881  		t.Run(singleTest.name, func(t *testing.T) {
   882  			expect := pa.isPortsAllocated(singleTest.input)
   883  			assert.Equal(t, expect, singleTest.expect)
   884  		})
   885  	}
   886  }
   887  
   888  func TestAllocate(t *testing.T) {
   889  	pSpace, err := newPortSpace(api.ProtocolTCP)
   890  	assert.NoError(t, err)
   891  
   892  	pConfig := &api.PortConfig{
   893  		Name:          "test1",
   894  		Protocol:      api.ProtocolTCP,
   895  		TargetPort:    30000,
   896  		PublishedPort: 30000,
   897  	}
   898  
   899  	// first consume 30000 in dynamicPortSpace
   900  	err = pSpace.allocate(pConfig)
   901  	assert.NoError(t, err)
   902  
   903  	pConfig = &api.PortConfig{
   904  		Name:          "test1",
   905  		Protocol:      api.ProtocolTCP,
   906  		TargetPort:    30000,
   907  		PublishedPort: 30000,
   908  	}
   909  
   910  	// consume 30000 again in dynamicPortSpace, got an error
   911  	err = pSpace.allocate(pConfig)
   912  	assert.Error(t, err)
   913  
   914  	pConfig = &api.PortConfig{
   915  		Name:          "test2",
   916  		Protocol:      api.ProtocolTCP,
   917  		TargetPort:    30000,
   918  		PublishedPort: 10000,
   919  	}
   920  
   921  	// consume 10000 in masterPortSpace, got no error
   922  	err = pSpace.allocate(pConfig)
   923  	assert.NoError(t, err)
   924  
   925  	pConfig = &api.PortConfig{
   926  		Name:          "test3",
   927  		Protocol:      api.ProtocolTCP,
   928  		TargetPort:    30000,
   929  		PublishedPort: 10000,
   930  	}
   931  
   932  	// consume 10000 again in masterPortSpace, got an error
   933  	err = pSpace.allocate(pConfig)
   934  	assert.Error(t, err)
   935  }