github.com/argoproj/argo-cd/v3@v3.2.1/controller/sharding/cache_test.go (about)

     1  package sharding
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  
     8  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
     9  	dbmocks "github.com/argoproj/argo-cd/v3/util/db/mocks"
    10  )
    11  
    12  func setupTestSharding(shard int, replicas int) *ClusterSharding {
    13  	shardingAlgorithm := "legacy" // we are using the legacy algorithm as it is deterministic based on the cluster id which is easier to test
    14  	db := &dbmocks.ArgoDB{}
    15  	return NewClusterSharding(db, shard, replicas, shardingAlgorithm).(*ClusterSharding)
    16  }
    17  
    18  func TestNewClusterSharding(t *testing.T) {
    19  	shard := 1
    20  	replicas := 2
    21  	sharding := setupTestSharding(shard, replicas)
    22  
    23  	assert.NotNil(t, sharding)
    24  	assert.Equal(t, shard, sharding.Shard)
    25  	assert.Equal(t, replicas, sharding.Replicas)
    26  	assert.NotNil(t, sharding.Shards)
    27  	assert.NotNil(t, sharding.Clusters)
    28  }
    29  
    30  func TestClusterSharding_Add(t *testing.T) {
    31  	shard := 1
    32  	replicas := 2
    33  	sharding := setupTestSharding(shard, replicas)
    34  
    35  	clusterA := &v1alpha1.Cluster{
    36  		ID:     "2",
    37  		Server: "https://127.0.0.1:6443",
    38  	}
    39  
    40  	sharding.Add(clusterA)
    41  
    42  	clusterB := v1alpha1.Cluster{
    43  		ID:     "1",
    44  		Server: "https://kubernetes.default.svc",
    45  	}
    46  
    47  	sharding.Add(&clusterB)
    48  
    49  	distribution := sharding.GetDistribution()
    50  
    51  	assert.Contains(t, sharding.Clusters, clusterA.Server)
    52  	assert.Contains(t, sharding.Clusters, clusterB.Server)
    53  
    54  	clusterDistribution, ok := distribution[clusterA.Server]
    55  	assert.True(t, ok)
    56  	assert.Equal(t, 1, clusterDistribution)
    57  
    58  	myClusterDistribution, ok := distribution[clusterB.Server]
    59  	assert.True(t, ok)
    60  	assert.Equal(t, 0, myClusterDistribution)
    61  
    62  	assert.Len(t, distribution, 2)
    63  }
    64  
    65  func TestClusterSharding_AddRoundRobin_Redistributes(t *testing.T) {
    66  	shard := 1
    67  	replicas := 2
    68  
    69  	db := &dbmocks.ArgoDB{}
    70  
    71  	sharding := NewClusterSharding(db, shard, replicas, "round-robin").(*ClusterSharding)
    72  
    73  	clusterA := &v1alpha1.Cluster{
    74  		ID:     "1",
    75  		Server: "https://127.0.0.1:6443",
    76  	}
    77  	sharding.Add(clusterA)
    78  
    79  	clusterB := v1alpha1.Cluster{
    80  		ID:     "3",
    81  		Server: "https://kubernetes.default.svc",
    82  	}
    83  	sharding.Add(&clusterB)
    84  
    85  	distributionBefore := sharding.GetDistribution()
    86  
    87  	assert.Contains(t, sharding.Clusters, clusterA.Server)
    88  	assert.Contains(t, sharding.Clusters, clusterB.Server)
    89  
    90  	clusterDistributionA, ok := distributionBefore[clusterA.Server]
    91  	assert.True(t, ok)
    92  	assert.Equal(t, 0, clusterDistributionA)
    93  
    94  	clusterDistributionB, ok := distributionBefore[clusterB.Server]
    95  	assert.True(t, ok)
    96  	assert.Equal(t, 1, clusterDistributionB)
    97  
    98  	assert.Len(t, distributionBefore, 2)
    99  
   100  	clusterC := v1alpha1.Cluster{
   101  		ID:     "2",
   102  		Server: "https://1.1.1.1",
   103  	}
   104  	sharding.Add(&clusterC)
   105  
   106  	distributionAfter := sharding.GetDistribution()
   107  
   108  	assert.Contains(t, sharding.Clusters, clusterA.Server)
   109  	assert.Contains(t, sharding.Clusters, clusterB.Server)
   110  	assert.Contains(t, sharding.Clusters, clusterC.Server)
   111  
   112  	clusterDistributionA, ok = distributionAfter[clusterA.Server]
   113  	assert.True(t, ok)
   114  	assert.Equal(t, 0, clusterDistributionA)
   115  
   116  	clusterDistributionC, ok := distributionAfter[clusterC.Server]
   117  	assert.True(t, ok)
   118  	assert.Equal(t, 1, clusterDistributionC) // will be assigned to shard 1 because the .ID is smaller then the "B" cluster
   119  
   120  	clusterDistributionB, ok = distributionAfter[clusterB.Server]
   121  	assert.True(t, ok)
   122  	assert.Equal(t, 0, clusterDistributionB) // will be reassigned to shard 0 because the .ID is bigger then the "C" cluster
   123  }
   124  
   125  func TestClusterSharding_Delete(t *testing.T) {
   126  	shard := 1
   127  	replicas := 2
   128  	sharding := setupTestSharding(shard, replicas)
   129  
   130  	sharding.Init(
   131  		&v1alpha1.ClusterList{
   132  			Items: []v1alpha1.Cluster{
   133  				{
   134  					ID:     "2",
   135  					Server: "https://127.0.0.1:6443",
   136  				},
   137  				{
   138  					ID:     "1",
   139  					Server: "https://kubernetes.default.svc",
   140  				},
   141  			},
   142  		},
   143  		&v1alpha1.ApplicationList{
   144  			Items: []v1alpha1.Application{
   145  				createApp("app2", "https://127.0.0.1:6443"),
   146  				createApp("app1", "https://kubernetes.default.svc"),
   147  			},
   148  		},
   149  	)
   150  
   151  	sharding.Delete("https://kubernetes.default.svc")
   152  	distribution := sharding.GetDistribution()
   153  	assert.Len(t, distribution, 1)
   154  }
   155  
   156  func TestClusterSharding_Update(t *testing.T) {
   157  	shard := 1
   158  	replicas := 2
   159  	sharding := setupTestSharding(shard, replicas)
   160  
   161  	sharding.Init(
   162  		&v1alpha1.ClusterList{
   163  			Items: []v1alpha1.Cluster{
   164  				{
   165  					ID:     "2",
   166  					Server: "https://127.0.0.1:6443",
   167  				},
   168  				{
   169  					ID:     "1",
   170  					Server: "https://kubernetes.default.svc",
   171  				},
   172  			},
   173  		},
   174  		&v1alpha1.ApplicationList{
   175  			Items: []v1alpha1.Application{
   176  				createApp("app2", "https://127.0.0.1:6443"),
   177  				createApp("app1", "https://kubernetes.default.svc"),
   178  			},
   179  		},
   180  	)
   181  
   182  	distributionBefore := sharding.GetDistribution()
   183  	assert.Len(t, distributionBefore, 2)
   184  
   185  	distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
   186  	assert.True(t, ok)
   187  	assert.Equal(t, 0, distributionA)
   188  
   189  	sharding.Update(&v1alpha1.Cluster{
   190  		ID:     "1",
   191  		Server: "https://kubernetes.default.svc",
   192  	}, &v1alpha1.Cluster{
   193  		ID:     "4",
   194  		Server: "https://kubernetes.default.svc",
   195  	})
   196  
   197  	distributionAfter := sharding.GetDistribution()
   198  	assert.Len(t, distributionAfter, 2)
   199  
   200  	distributionA, ok = distributionAfter["https://kubernetes.default.svc"]
   201  	assert.True(t, ok)
   202  	assert.Equal(t, 1, distributionA)
   203  }
   204  
   205  func TestClusterSharding_UpdateServerName(t *testing.T) {
   206  	shard := 1
   207  	replicas := 2
   208  	sharding := setupTestSharding(shard, replicas)
   209  
   210  	sharding.Init(
   211  		&v1alpha1.ClusterList{
   212  			Items: []v1alpha1.Cluster{
   213  				{
   214  					ID:     "2",
   215  					Server: "https://127.0.0.1:6443",
   216  				},
   217  				{
   218  					ID:     "1",
   219  					Server: "https://kubernetes.default.svc",
   220  				},
   221  			},
   222  		},
   223  		&v1alpha1.ApplicationList{
   224  			Items: []v1alpha1.Application{
   225  				createApp("app2", "https://127.0.0.1:6443"),
   226  				createApp("app1", "https://kubernetes.default.svc"),
   227  			},
   228  		},
   229  	)
   230  
   231  	distributionBefore := sharding.GetDistribution()
   232  	assert.Len(t, distributionBefore, 2)
   233  
   234  	distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
   235  	assert.True(t, ok)
   236  	assert.Equal(t, 0, distributionA)
   237  
   238  	sharding.Update(&v1alpha1.Cluster{
   239  		ID:     "1",
   240  		Server: "https://kubernetes.default.svc",
   241  	}, &v1alpha1.Cluster{
   242  		ID:     "1",
   243  		Server: "https://server2",
   244  	})
   245  
   246  	distributionAfter := sharding.GetDistribution()
   247  	assert.Len(t, distributionAfter, 2)
   248  
   249  	_, ok = distributionAfter["https://kubernetes.default.svc"]
   250  	assert.False(t, ok) // the old server name should not be present anymore
   251  
   252  	_, ok = distributionAfter["https://server2"]
   253  	assert.True(t, ok) // the new server name should be present
   254  }
   255  
   256  func TestClusterSharding_IsManagedCluster(t *testing.T) {
   257  	replicas := 2
   258  	sharding0 := setupTestSharding(0, replicas)
   259  
   260  	sharding0.Init(
   261  		&v1alpha1.ClusterList{
   262  			Items: []v1alpha1.Cluster{
   263  				{
   264  					ID:     "1",
   265  					Server: "https://kubernetes.default.svc",
   266  				},
   267  				{
   268  					ID:     "2",
   269  					Server: "https://127.0.0.1:6443",
   270  				},
   271  			},
   272  		},
   273  		&v1alpha1.ApplicationList{
   274  			Items: []v1alpha1.Application{
   275  				createApp("app2", "https://127.0.0.1:6443"),
   276  				createApp("app1", "https://kubernetes.default.svc"),
   277  			},
   278  		},
   279  	)
   280  
   281  	assert.True(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
   282  		ID:     "1",
   283  		Server: "https://kubernetes.default.svc",
   284  	}))
   285  
   286  	assert.False(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
   287  		ID:     "2",
   288  		Server: "https://127.0.0.1:6443",
   289  	}))
   290  
   291  	sharding1 := setupTestSharding(1, replicas)
   292  
   293  	sharding1.Init(
   294  		&v1alpha1.ClusterList{
   295  			Items: []v1alpha1.Cluster{
   296  				{
   297  					ID:     "2",
   298  					Server: "https://127.0.0.1:6443",
   299  				},
   300  				{
   301  					ID:     "1",
   302  					Server: "https://kubernetes.default.svc",
   303  				},
   304  			},
   305  		},
   306  		&v1alpha1.ApplicationList{
   307  			Items: []v1alpha1.Application{
   308  				createApp("app2", "https://127.0.0.1:6443"),
   309  				createApp("app1", "https://kubernetes.default.svc"),
   310  			},
   311  		},
   312  	)
   313  
   314  	assert.False(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
   315  		ID:     "1",
   316  		Server: "https://kubernetes.default.svc",
   317  	}))
   318  
   319  	assert.True(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
   320  		ID:     "2",
   321  		Server: "https://127.0.0.1:6443",
   322  	}))
   323  }
   324  
   325  func TestClusterSharding_ClusterShardOfResourceShouldNotBeChanged(t *testing.T) {
   326  	shard := 1
   327  	replicas := 2
   328  	sharding := setupTestSharding(shard, replicas)
   329  
   330  	Int64Ptr := func(i int64) *int64 {
   331  		return &i
   332  	}
   333  
   334  	clusterWithNil := &v1alpha1.Cluster{
   335  		ID:     "2",
   336  		Server: "https://127.0.0.1:6443",
   337  		Shard:  nil,
   338  	}
   339  
   340  	clusterWithValue := &v1alpha1.Cluster{
   341  		ID:     "1",
   342  		Server: "https://kubernetes.default.svc",
   343  		Shard:  Int64Ptr(1),
   344  	}
   345  
   346  	clusterWithToBigValue := &v1alpha1.Cluster{
   347  		ID:     "3",
   348  		Server: "https://1.1.1.1",
   349  		Shard:  Int64Ptr(999), // shard value is explicitly bigger than the number of replicas
   350  	}
   351  
   352  	sharding.Init(
   353  		&v1alpha1.ClusterList{
   354  			Items: []v1alpha1.Cluster{
   355  				*clusterWithNil,
   356  				*clusterWithValue,
   357  				*clusterWithToBigValue,
   358  			},
   359  		},
   360  		&v1alpha1.ApplicationList{
   361  			Items: []v1alpha1.Application{
   362  				createApp("app2", "https://127.0.0.1:6443"),
   363  				createApp("app1", "https://kubernetes.default.svc"),
   364  			},
   365  		},
   366  	)
   367  	distribution := sharding.GetDistribution()
   368  	assert.Len(t, distribution, 3)
   369  
   370  	assert.Nil(t, sharding.Clusters[clusterWithNil.Server].Shard)
   371  
   372  	assert.NotNil(t, sharding.Clusters[clusterWithValue.Server].Shard)
   373  	assert.Equal(t, int64(1), *sharding.Clusters[clusterWithValue.Server].Shard)
   374  	assert.Equal(t, 1, distribution[clusterWithValue.Server])
   375  
   376  	assert.NotNil(t, sharding.Clusters[clusterWithToBigValue.Server].Shard)
   377  	assert.Equal(t, int64(999), *sharding.Clusters[clusterWithToBigValue.Server].Shard)
   378  	assert.Equal(t, 0, distribution[clusterWithToBigValue.Server]) // will be assigned to shard 0 because the value is bigger than the number of replicas
   379  }
   380  
   381  func TestHasShardingUpdates(t *testing.T) {
   382  	Int64Ptr := func(i int64) *int64 {
   383  		return &i
   384  	}
   385  
   386  	testCases := []struct {
   387  		name     string
   388  		old      *v1alpha1.Cluster
   389  		new      *v1alpha1.Cluster
   390  		expected bool
   391  	}{
   392  		{
   393  			name: "No updates",
   394  			old: &v1alpha1.Cluster{
   395  				Server: "https://kubernetes.default.svc",
   396  				Shard:  Int64Ptr(1),
   397  			},
   398  			new: &v1alpha1.Cluster{
   399  				Server: "https://kubernetes.default.svc",
   400  				Shard:  Int64Ptr(1),
   401  			},
   402  			expected: false,
   403  		},
   404  		{
   405  			name: "Updates",
   406  			old: &v1alpha1.Cluster{
   407  				Server: "https://kubernetes.default.svc",
   408  				Shard:  Int64Ptr(1),
   409  			},
   410  			new: &v1alpha1.Cluster{
   411  				Server: "https://kubernetes.default.svc",
   412  				Shard:  Int64Ptr(2),
   413  			},
   414  			expected: true,
   415  		},
   416  		{
   417  			name: "Old is nil",
   418  			old:  nil,
   419  			new: &v1alpha1.Cluster{
   420  				Server: "https://kubernetes.default.svc",
   421  				Shard:  Int64Ptr(2),
   422  			},
   423  			expected: false,
   424  		},
   425  		{
   426  			name: "New is nil",
   427  			old: &v1alpha1.Cluster{
   428  				Server: "https://kubernetes.default.svc",
   429  				Shard:  Int64Ptr(2),
   430  			},
   431  			new:      nil,
   432  			expected: false,
   433  		},
   434  		{
   435  			name:     "Both are nil",
   436  			old:      nil,
   437  			new:      nil,
   438  			expected: false,
   439  		},
   440  		{
   441  			name: "Both shards are nil",
   442  			old: &v1alpha1.Cluster{
   443  				Server: "https://kubernetes.default.svc",
   444  				Shard:  nil,
   445  			},
   446  			new: &v1alpha1.Cluster{
   447  				Server: "https://kubernetes.default.svc",
   448  				Shard:  nil,
   449  			},
   450  			expected: false,
   451  		},
   452  		{
   453  			name: "Old shard is nil",
   454  			old: &v1alpha1.Cluster{
   455  				Server: "https://kubernetes.default.svc",
   456  				Shard:  nil,
   457  			},
   458  			new: &v1alpha1.Cluster{
   459  				Server: "https://kubernetes.default.svc",
   460  				Shard:  Int64Ptr(2),
   461  			},
   462  			expected: true,
   463  		},
   464  		{
   465  			name: "New shard is nil",
   466  			old: &v1alpha1.Cluster{
   467  				Server: "https://kubernetes.default.svc",
   468  				Shard:  Int64Ptr(2),
   469  			},
   470  			new: &v1alpha1.Cluster{
   471  				Server: "https://kubernetes.default.svc",
   472  				Shard:  nil,
   473  			},
   474  			expected: true,
   475  		},
   476  		{
   477  			name: "Cluster ID has changed",
   478  			old: &v1alpha1.Cluster{
   479  				ID:     "1",
   480  				Server: "https://kubernetes.default.svc",
   481  				Shard:  Int64Ptr(2),
   482  			},
   483  			new: &v1alpha1.Cluster{
   484  				ID:     "2",
   485  				Server: "https://kubernetes.default.svc",
   486  				Shard:  Int64Ptr(2),
   487  			},
   488  			expected: true,
   489  		},
   490  		{
   491  			name: "Server has changed",
   492  			old: &v1alpha1.Cluster{
   493  				ID:     "1",
   494  				Server: "https://server1",
   495  				Shard:  Int64Ptr(2),
   496  			},
   497  			new: &v1alpha1.Cluster{
   498  				ID:     "1",
   499  				Server: "https://server2",
   500  				Shard:  Int64Ptr(2),
   501  			},
   502  			expected: true,
   503  		},
   504  	}
   505  
   506  	for _, tc := range testCases {
   507  		t.Run(tc.name, func(t *testing.T) {
   508  			assert.Equal(t, tc.expected, hasShardingUpdates(tc.old, tc.new))
   509  		})
   510  	}
   511  }